;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;***********************************************************************
;
;   Module          = EDDHBBLT
;
;   Description     = Private Blt code
;
;   Function        = Blt interface to Expressway hardware
;
;
;***********************************************************************

; NOTE : in the new scheme this low level routine is called with
;        a number of clip regions in the cache - this number can vary
;        from 1 to the size of the cache
;        Previously if passed 1 clip rectangle this meant that the
;        engine only had 1 clip rectangle, and hence it was true that
;        the destination was already clipped by the calling code.
;        However in the new scheme if the engine has say one more
;        clip region than can fit in the cache then the low level
;        routine is called twice, the second time with just one clip
;        region though no preclipping has been done by the calling
;        routine

INCL_GPIBITMAPS EQU     1
include os2.inc
include eddinclt.inc

include eddhcone.inc
include eddhmacr.inc
include eddhtype.inc

include eddfcone.inc
include eddfmacr.inc
include eddftype.inc
IFDEF _8514
?DF     equ     1                                                       ;**
include cmacros.inc
include 8514.inc
include eddconse.inc
include cacheman.inc
ENDIF

IF1
;----------------------------------------------------------------------
; fast 3X multiplication.  is it really any faster w/ 387 or 486DX?
;----------------------------------------------------------------------
fast3x  macro   regsrc, regtmp
        mov     regtmp, regsrc
        shl     regsrc, 1
        add     regsrc, regtmp
        endm

;----------------------------------------------------------------------
; takes P0|P1|P2|P3 in AX and outputs to DX port
;----------------------------------------------------------------------
SendBits16      macro
        IFNDEF S3
        rol     al,4                    ; now       P0|P1|P3|P2
        rol     ax,4                    ; now       P1|P3|P2|P0
        rol     ah,4                    ; now       P3|P1|P2|P0
        rol     ax,1                    ; P0,P1 into hw position
        out     dx,ax                   ; output P0,P1
        ror     ax,4                    ; P2,P3 into hw position
        out     dx,ax                   ; output P2,P3
        ELSE
        xchg    ah,al
        out     dx,ax
        ENDIF
        endm

;----------------------------------------------------------------------
; extracts and saves bits for phase shifting
;----------------------------------------------------------------------
SavePhaseBits macro datareg, savereg
        mov     savereg, datareg        ; cache new unused pixels
        not     ch                      ; form left mask
        and     savereg, ch             ; isolate new unused pixels
        not     ch                      ; restore right mask
        endm

GetPhaseBits macro datareg, getreg
        and     datareg, ch             ; make room for old unused pixels
        or      datareg, getreg         ; add in old unused pixels
        endm

;----------------------------------------------------------------------
; aligns bytes in AL, AH
;----------------------------------------------------------------------
DoPhaseShift macro
        xchg    ah,al                   ; now P0|P1|P2|P3
        ror     ax,cl                   ; align to destination
        SavePhaseBits ah, bl            ; rightmost bits from AH to BL
        GetPhaseBits ah, bh             ; rightmost bits from BH to AH
        mov     bh, bl                  ; save new unused pels in BH
        endm

ENDIF ; PASS1

;***********************************************************************
; define global variables
;***********************************************************************
pixelop          equ <_pixelop>
AIxfer           equ <_AIxfer>
IFNDEF   _8514
pXGARegs         equ <_pXGARegs>
ELSE
p8514Regs        equ <_p8514Regs>
extrn _Screen8514VisHeight :dword
extrn _pPhunkVirt          :dword
extrn _pCacheMap           :dword
extrn _pHWMap              :dword
IFDEF   MEMMAPIO
pVRAM            equ <_pVRAM>
ENDIF
ENDIF
colorpatphysical equ <_colorpatphysical>
monopatphysical  equ <_monopatphysical>
newpatterntable  equ <_newpatterntable>
directlistentry  equ <_directlistentry>

extrn pixelop           :dword
extrn AIxfer            :dword
IFNDEF   _8514
extrn pXGARegs          :dword
ELSE
EXTRN _CopyMemoryToVRAM:NEAR
IFDEF   BPP24
EXTRN _Copy24MonoToVRAM:NEAR
EXTRN _Copy24MonoMixToVRAM:NEAR
ENDIF   ;BPP24
EXTRN _ColorPat        :dword
extrn _DDT             :byte
extrn p8514Regs        :dword
IFDEF   MEMMAPIO
extrn   pVRAM           :dword
ENDIF
ENDIF
extrn colorpatphysical  :dword
extrn monopatphysical   :dword
extrn newpatterntable   :dword
extrn directlistentry   :dword

extrn _pbHWPollRegister :dword
extrn _Pattern          :dword

PATTERN_SIZE  equ   100
;***********************************************************************
; handle the soft draw/hard draw differences
;***********************************************************************
IFDEF HARD_DRAW
public  _eddh_SrcDestBlt
public  _eddh_PatDestBlt
public  _eddh_DestOnlyBlt

SrcDestBlt      equ     <_eddh_SrcDestBlt>
PatDestBlt      equ     <_eddh_PatDestBlt>
DestOnlyBlt     equ     <_eddh_DestOnlyBlt>
bitmap_address  equ     phys_addr
ENDIF ; HARD_DRAW

IFDEF SOFT_DRAW
public  _eddf_SrcDestBlt
public  _eddf_PatDestBlt
public  _eddf_DestOnlyBlt

SrcDestBlt      equ     <_eddf_SrcDestBlt>
PatDestBlt      equ     <_eddf_PatDestBlt>
DestOnlyBlt     equ     <_eddf_DestOnlyBlt>
bitmap_address  equ     virt_addr

extrn _eddf_MESS        :proc
ENDIF ; SOFT_DRAW


; dither externs


;***********************************************************************
; Set up structure for parameter block access
;***********************************************************************
BITBLTPB                struc
pbmhDest                dd      ?
cDestClipRects          dw      ?
pNextDestClipRect       dd      ?
Dest0Coord              dd      ?
Dest1Coord              dd      ?
pbmhSrc                 dd      ?
Src0Coord               dd      ?
Src1Coord               dd      ?
PatOrig                 dd      ?
; NB the C version of this structure has extra fields defined from here on
BITBLTPB                ends

_DATA           segment dword use32 public 'DATA'
_DATA           ends

_TEXT           segment use32 dword public 'CODE'
                assume  cs:FLAT, ds:FLAT, es:FLAT

;***********************************************************************
;
; Function: SrcDestBlt
;
; Called by: eddb_bitblt in eddnbblt.c
;
; Purpose: carries out a bitblt operation for a source and destination
; rop.
; Assumes the calling function has not made the call until the hardware
; is free
;
;***********************************************************************
        align   4
SrcDestBlt proc near
        push    esi
        push    edi
        push    ebx
        IFNDEF  _8514
        pushxga

; get the base address of the hardware registers
        movxga  pXGARegs
        ELSE
        mov     esi,p8514Regs
        ENDIF

; use ebx as a pointer to the destination bitmap header
        mov     ebx, AIxfer.pbmhDest

; use edi to count the number of clip regions
        movzx   edi, word ptr AIxfer.cDestClipRects

; select the destination map
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; write destination bitmap address to hardware mapA base
        mov             eax, [ebx].bitmap_address
        IFDEF  _8514
        IFDEF  HARD_DRAW
        and     eax,0fffffffh   ; clear the vram marker
        ENDIF
        ENDIF
        memregwrite     pi_map_base_ptr_A, eax

; write mapA width and height from bitmap header
        mov             eax, dword ptr [ebx].hw_width
        memregwrite     pi_map_size_A, eax

; write mapA format from bitmap header
        mov             al, byte ptr [ebx].hw_format
        memregwrite     pi_map_format_A, al


; use ebx as a pointer to the source bitmap header
        mov     ebx, AIxfer.pbmhSrc

; if the source format differs from the dest then we are doing an
; expansion from 1 bit per pixel to screen format. To do this the blt
; must be done using the pattern and destination maps, otherwise the
; source and destination maps are used
; the format is held in bits 0 - 2 so mask off these in al (the
; destination format and compare with the same bits in the source format
; bit 3 of the format value indicates motorola or intel bit organisation
; and other bits are unused (0)
        mov             cl, byte ptr [ebx].hw_format
        xor             al, cl
        and             al, 07h
        jz              short not_expanding

; select the pattern map
        memregwrite     pi_map_index_C, SEL_PIX_MAP_C


; write mapC format: this must be one (and always motorola)
        memregwrite     pi_map_format_C, MOTOROLA+ONE_BPP

; write source bitmap address to hardware mapC base
        mov     eax, [ebx].bitmap_address
        IFDEF  _8514
        IFDEF  HARD_DRAW
        and     eax,0fffffffh   ; clear the vram marker
        ENDIF
        ENDIF
        memregwrite     pi_map_base_ptr_C, eax

; write mapC width and height from bitmap header
        mov             eax, dword ptr [ebx].hw_width
        memregwrite     pi_map_size_C, eax
        jmp             short completed_sourcemap

not_expanding:
; select the source map
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B


; write mapB format: this must be the same as mapA (which is already
; in cl)
        memregwrite     pi_map_format_B, cl

; write source bitmap address to hardware mapB base
        mov             eax, [ebx].bitmap_address
        IFDEF  _8514
        IFDEF  HARD_DRAW
        and     eax,0fffffffh   ; clear the vram marker
        ENDIF
        ENDIF
        memregwrite     pi_map_base_ptr_B, eax

; write mapB width and height from bitmap header
        mov             eax, dword ptr [ebx].hw_width
        memregwrite     pi_map_size_B, eax

completed_sourcemap:

; use ebx to reference the clip rectangles
        mov             ebx, dword ptr AIxfer.pNextDestClipRect

; get the pixel op out the parameter block
        mov             edx, pixelop

        jmp             short srcdest_decclip


srcdest_writepixop:

; wait for the h/w to be free before writing to the registers

        IFNDEF  _8514
        waitshort
        ENDIF
        memregwrite     dimensions, eax

; source x coordinate is pointed to by ss:esp; pop it into cx (y coord in
; ecx high word) and write the source coordinates to the hardware
        pop             cx

; The pixel op will be doing either a pattern expansion or a scr to dest
; blt at this point.  Since we dont know which of these it is we set
; both the src and patt map, though this is fine since only one will
; appear in the pixel op
        memregwrite     src_map, ecx
        memregwrite     patt_map, ecx

; ss:esp now points to the destination coordinates: pop these straight into
; the hardware
        pop     eax
        memregwrite     dest_map, eax

; write the pixel op to kick off the blt
        memregwrite     pixel_op, edx

IFDEF HARD_DRAW

; see if the source is vram or not by checking vram marker
        IFDEF   _8514
        push    ebx
        mov     ebx, AIxfer.pbmhSrc
        mov     eax, [ebx].bitmap_address
        and     eax, 0f0000000h
        cmp     eax, 0f0000000h
        pop     ebx
        jz      short @f
        call    SoftSrcSpecialist
        jmp     short soft_done

@@:     call    SrcSpecialist

soft_done:
        ENDIF   ;_8514

ELSE

        saveregs
        call    _eddf_MESS
        restoreregs

ENDIF

srcdest_no_intersect:
; if the clip region counter is zero there is nothing more to do
        or      edi, edi
        jnz     short srcdest_nextclip
        IFNDEF  _8514
        popxga
        ENDIF
        pop     ebx
        pop     edi
        pop     esi
        ret

srcdest_nextclip:
; advance the pointer to the clip rectangles to give us access to the next
; clip
        add     ebx, len_clip_rect

srcdest_decclip:
; decrement the clip region counter
        dec     edi

srcdest_doclipping:
; the parameter block coordinates are ordered for a left to right
; blt: any other direction requires reordering

; the parameter block coordinates are ordered for a top to bottom
; blt: any other direction requires reordering
        test            dl, OCT_DY_BIT
        jnz             short srcdest_bottomtop

; top to bottom:
; find the maximum of the clip bottom edge and the destination bottom
; edge
; if the destination is clipped, an adjustment must be made to the
; source. The source y coord is saved in ecx high word
        mov             cx, AIxfer.Src0Coord.y
        mov             ax, AIxfer.Dest0Coord.y
        cmp             ax, [ebx].clip_y0
        jnc             short @F
        sub             cx, ax
        mov             ax, [ebx].clip_y0
        add             cx, ax
@@:     shl             ecx, 10h

; find the minimum of the distances from the bottom edge (in ax) to
; the top edge of the bitmap and top edge of the target: put the
; value in the eax high word
; if there is no intersection with the clip rectangle then clean up
; the stack and go check out any other clips
; cx has the destination y coordinate moved into it: this must be
; saved on the stack (to avoid a waitshort until later) before cx is
; altered
        mov             cx, ax
        sub             ax, [ebx].clip_y1
        ja              srcdest_no_intersect
        push            cx
        sub             cx, AIxfer.Dest1Coord.y
        jbe             short @F
        add             esp, 2
        jmp             srcdest_no_intersect
@@:     rmax            ax, cx
        neg             ax
        shl             eax, 10h

; find the horizontal blt direction and jump to the code to handle it
        test            dl, OCT_DX_BIT
        jz              short srcdest_leftright
        jmp             srcdest_rightleft


srcdest_bottomtop:
; bottom to top:
; find the minimum of the clip top edge and the destination top
; edge
; if the destination is clipped, an adjustment must be made to the
; source before saving it in ecx high word
        mov             cx, AIxfer.Src1Coord.y
        mov             ax, AIxfer.Dest1Coord.y
        cmp             ax, [ebx].clip_y1
        jbe             short @F
        sub             cx, ax
        mov             ax, [ebx].clip_y1
        add             cx, ax
@@:     shl             ecx, 10h

; find the minimum of the distances from the top edge (in ax) to the
; bottom edge of the bitmap and bottom edge of the target: put the value
; in the eax high word
; if there is no intersection with the clip rectangle then clean up
; the stack and go check out any other clips
; ax holds the destination y coordinate: this must be
; saved on the stack (to avoid a waitshort until later) before ax is
; altered
        mov             cx, ax
        sub             cx, AIxfer.Dest0Coord.y
        jc              srcdest_no_intersect
        push            ax
        sub             ax, [ebx].clip_y0
        jnc             short @F
        add             esp, 2
        jmp             srcdest_no_intersect
@@:     rmin            ax, cx
        shl             eax, 10h

; determine the horizontal blt direction
        test            dl, OCT_DX_BIT
        jnz             short srcdest_rightleft

srcdest_leftright:
; find the maximum of the clip left edge and the destination left edge
; and save on the stack
; if the destination is clipped, an adjustment must be made to the
; source before saving on the stack
        mov             cx, AIxfer.Src0Coord.x
        mov             ax, AIxfer.Dest0Coord.x
        cmp             ax, [ebx].clip_x0
;#74698 jnc             short @F
        jge             short @F
        sub             cx, ax
        mov             ax, [ebx].clip_x0
        add             cx, ax
@@:     push            ax
        push            cx

; find the minimum of the distances from the left edge (in ax) to the
; right edge of the bitmap and right edge of the target: put the value
; in the dimension register (y dimension is in eax high word)
; if there is no intersection with the clip rectangle then clean up
; the stack (remove destination coordinates and source x coordinate) and
; go back to look for more clips
        mov             cx, ax
        sub             ax, AIxfer.Dest1Coord.x
        jbe             short @F
        add             esp, 6
        jmp             srcdest_no_intersect
@@:     sub             cx, [ebx].clip_x1
        jbe             short @F
        add             esp, 6
        jmp             srcdest_no_intersect
@@:     rmax            ax, cx
        neg             ax

; go do the blt
        jmp             srcdest_writepixop


srcdest_rightleft:
; right to left:
; find the minimum of the clip right edge and the destination right
; edge and save on the stack for now
; if the destination is clipped, an adjustment must be made to the
; source before saving it on the stack
        mov             cx, AIxfer.Src1Coord.x
        mov             ax, AIxfer.Dest1Coord.x
        cmp             ax, [ebx].clip_x1
        jbe             short @F
        sub             cx, ax
        mov             ax, [ebx].clip_x1
        add             cx, ax
@@:     push            ax
        push            cx

; find the minimum of the distances from the right edge (in ax) to the
; left edge of the bitmap and left edge of the target: put the value
; in the x dimension register
; if there is no intersection with the clip rectangle then clean up
; the stack (remove destination coordinates and source x coordinate) and
; go back to look for more clips
        mov             cx, ax
        sub             ax, AIxfer.Dest0Coord.x
        jnc             short @F
        add             esp, 6
        jmp             srcdest_no_intersect
@@:     sub             cx, [ebx].clip_x0
        jnc             short @F
        add             esp, 6
        jmp             srcdest_no_intersect
@@:     rmin            ax, cx

; go do the blt
        jmp             srcdest_writepixop


SrcDestBlt   endp

IFDEF   _8514
IFDEF   HARD_DRAW
        page
;----------------------------Private-Routine----------------------------;
; SrcSpecialist
;
; Entry:
; Returns:
;       None
; Error Returns:
;       None
; Registers Destroyed:
;       Ax,Cx,Dx,Si,FLAGS
; Registers Preserved:
;       Bx,Di,Bp,Ds,Es
; Calls:
;       None
; History:
;-----------------------------------------------------------------------;

;------------------------------Pseudo-Code------------------------------;
; {
; }
;-----------------------------------------------------------------------;

        align   4
cProc   SrcSpecialist, <PUBLIC,NODATA,NEAR>, <edi,esi,ebx,edx,ebp>

        localW  x_src
        localW  y_src
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        localW  blt_dir
cBegin

; use ebx as a pointer to the destination bitmap header
        mov     ebx, AIxfer.pbmhDest

; convert destination bitmap address to x and y for 8514 hardware
        memregread      eax,dest_map
        mov     x_dst,ax
        ror     eax,16
        mov     y_dst,ax
        calc8514xy  [ebx].bitmap_address
        add     x_dst,dx
        add     y_dst,ax

IFDEF   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        movzx   eax,x_dst
        mov     dx,3
        mul     dx
        mov     edi,pixelop             ; Defect 74269
        test    edi,BLTDIR_RIGHTTOLEFT  ; going right to left?
        jz      short LeftToRight       ; no
        add     ax,2                    ; yes
LeftToRight:
        mov     x_dst,ax
@@:
ENDIF

; set up the destination width and height
; use the clip rect set up in srcdestblt routine
        memregread      ax,dim1
IFDEF   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
@@:
ENDIF
        mov     total_width,ax
        memregread      ax,dim2
        mov     total_height,ax

; use ebx as a pointer to the source bitmap header
; - which will be found in the same place as the source bm header
        mov     ebx, AIxfer.pbmhSrc

; select the source bitmap map
        memregread      eax,src_map
        mov     x_src,ax
        ror     eax,16
        mov     y_src,ax
        calc8514xy  [ebx].bitmap_address
        add     x_src,dx
        add     y_src,ax

IFDEF   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        movzx   eax,x_src
        mov     dx,3
        mul     dx
        mov     edi,pixelop             ; Defect 74269
        test    edi,BLTDIR_RIGHTTOLEFT  ; going right to left?
        jz      short LeftToRight2      ; no
        add     ax,2                    ; yes
LeftToRight2:
        mov     x_src,ax
@@:
ENDIF

; A simple case of blt'ing between 2 bitmaps on the board.

        mov     edi,pixelop             ; flag with directions we are blt'ing
        mov     blt_dir,CMD_DX+CMD_DY   ; set my flag to +x +y

        WaitQIdle
        WaitQ   3
        memregread      eax, Mode
        and     eax, MD_UNDERPAINT      ; get underpaint test code
        or      eax, MODE_2DECODE+MD_PS_ONES
        outwQ   MODE, ax
        memregread      eax,Function_1
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_COPY        ; variable data mode
        outwQ   FUNCTION_1,ax
        memregread      eax,Function_0
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_COPY        ; variable data mode
        outwQ   FUNCTION_0,ax

        WaitQ   7
        mov     ax,x_src                ; src operand x origin
        mov     cx,x_dst                ; dest operand x origin
        mov     si,total_width          ; 0-based x extent
        test    edi,BLTDIR_RIGHTTOLEFT  ; x++ ?
        jz      short @F                ; yes...
        and     blt_dir,CMD_DY          ; clear +x bit
@@:     outwQ   X0,ax                   ; output src x origin
        outwQ   X1,cx                   ; output dest x origin
        outwQ   LX,si                   ; output 0-based x extent of blt

        mov     ax,y_src                ; src operand y origin
        mov     cx,y_dst                ; dest operand y origin
        mov     si,total_height         ; 0-based y extent
        test    edi,BLTDIR_BOTTOMTOTOP  ; y++ ?
        jz      short @F                ; yes...
        and     blt_dir,CMD_DX          ; clear +y bit
@@:     outwQ   Y0,ax                   ; output src y origin
        outwQ   Y1,cx                   ; output dest y origin
        outwQ   LY,si                   ; output 0-based y extent of blt

        mov     ax,CMDSRCSCR            ; src is screen command
        or      ax,blt_dir              ; add in blt directions
        outwQ   CMD_FLAGS,ax            ; output command
cEnd

;----------------------------Private-Routine----------------------------;
; DumpOffScreenVRAM
;
; Entry:
; Returns:
;       None
; Error Returns:
;       None
; Registers Destroyed:
;       Ax,Cx,Dx,Si,FLAGS
; Registers Preserved:
;       Bx,Di,Bp,Ds,Es
; Calls:
;       None
; History:
;-----------------------------------------------------------------------;

;------------------------------Pseudo-Code------------------------------;
; {
; }
;-----------------------------------------------------------------------;

        align   4
cProc   DVRAM, <PUBLIC,NODATA,NEAR>, <edi,esi,ebx,ebp>

        localW  x_src
        localW  y_src
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        localW  blt_dir
cBegin

; select off-screen VRAM as the source
        mov     x_src,0
        mov     ax,WORD PTR _Screen8514VisHeight
        mov     y_src,ax

; convert destination bitmap address to x and y for 8514 hardware
        mov     x_dst,0
        mov     y_dst,0

; set up the destination width and height
; use the size of off-screen VRAM
        IFNDEF  S3
        mov     total_width,SCR_8514_WIDTH-1
        ELSE
        mov     total_width,SCR_S3_WIDTH-1
        ENDIF
        mov     total_height,255


; A simple case of blt'ing between 2 bitmaps on the board.

        WaitQIdle

        WaitQ   2
        outwQ   READ_ENABLE,0FFFFh
        outwQ   WRITE_ENABLE,0FFFFh

        WaitQ   8

        mov     ax,x_src                ; src operand x origin
        outwQ   X0,ax                   ; output src x origin

        mov     ax,y_src                ; src operand y origin
        outwQ   Y0,ax                   ; output src y origin

        mov     ax,x_dst                ; dest operand x origin
        outwQ   X1,ax                   ; output dest x origin

        mov     ax,y_dst                ; dest operand y origin
        outwQ   Y1,ax                   ; output dest y origin

        mov     ax,total_width          ; 0-based x extent
        outwQ   LX,ax                   ; output 0-based x extent of blt

        mov     ax,total_height         ; 0-based y extent
        outwQ   LY,ax                   ; output 0-based y extent of blt

        mov     ax,FUNC_2OP_COPY + FUNC_S
        outwQ   FUNCTION_1,ax

        mov     ax,MODE_2DECODE + MD_PS_ONES + MD_UP_FALSE
        outwQ   MODE,ax

        WaitQ   1
        mov     ax,CMDSRCSCR + CMD_DX + CMD_DY
        outwQ   CMD_FLAGS,ax            ; output command

cEnd

;----------------------------Private-Routine----------------------------;
; DumpOffScreenVRAMFontCache
;
; Entry:
; Returns:
;       None
; Error Returns:
;       None
; Registers Destroyed:
;       Ax,Cx,Dx,Si,FLAGS
; Registers Preserved:
;       Bx,Di,Bp,Ds,Es
; Calls:
;       None
; History:
;-----------------------------------------------------------------------;

;------------------------------Pseudo-Code------------------------------;
; {
; }
;-----------------------------------------------------------------------;

FONT_CACHE_POS  equ SCR_8514_VIS_HEIGHT + 128

        align   4
cProc   DVRAMFonts, <PUBLIC,NODATA,NEAR>, <edi,esi,ebx,ebp>

        localW  x_src
        localW  y_src
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        localW  blt_dir
cBegin

; select off-screen VRAM as the source
        mov     x_src,0
        mov     ax,WORD PTR _Screen8514VisHeight
        mov     y_src,ax

; convert destination bitmap address to x and y for 8514 hardware
        mov     x_dst,0
        mov     y_dst,0

; set up the destination width and height
; use the size of off-screen VRAM
        IFNDEF  S3
        mov     total_width,SCR_8514_WIDTH-1
        ELSE
        mov     total_width,SCR_S3_WIDTH-1
        ENDIF
        mov     total_height,SCR_8514_HEIGHT-FONT_CACHE_POS-1


; A simple case of blt'ing between 2 bitmaps on the board.

        mov     bx,80h

next_plane:

        WaitQIdle

        WaitQ   8

        mov     ax,x_src                ; src operand x origin
        outwQ   X0,ax                   ; output src x origin

        mov     ax,y_src                ; src operand y origin
        outwQ   Y0,ax                   ; output src y origin

        mov     ax,x_dst                ; dest operand x origin
        outwQ   X1,ax                   ; output dest x origin

        mov     ax,y_dst                ; dest operand y origin
        outwQ   Y1,ax                   ; output dest y origin

        mov     ax,total_width          ; 0-based x extent
        outwQ   LX,ax                   ; output 0-based x extent of blt

        mov     ax,total_height         ; 0-based y extent
        outwQ   LY,ax                   ; output 0-based y extent of blt

        mov     ax,FUNC_2OP_COL0 + FUNC_S
        outwQ   FUNCTION_0,ax

        mov     ax,FUNC_2OP_COL1 + FUNC_S
        outwQ   FUNCTION_1,ax

        WaitQ   5

        outwQ   COLOR_0,0FFh
        outwQ   COLOR_1,00

        outwQ   READ_ENABLE,bx

        outwQ   WRITE_ENABLE,0FFFFh

        mov     ax,MODE_2DECODE + MD_PS_COPY
        outwQ   MODE,ax

        WaitQ   1
        mov     ax,CMDSRCSCR + CMD_DX + CMD_DY
        outwQ   CMD_FLAGS,ax            ; output command

        int     3                       ; pause between plane dumps

        shr     bx,1
        cmp     bx,0
        jnz     next_plane

cEnd

page

;----------------------------Private-Routine----------------------------;
; SoftSrcSpecialist
;
; Entry:
; Returns:
;       None
; Error Returns:
;       None
; Registers Destroyed:
;       Ax,Cx,Dx,Si,FLAGS
; Registers Preserved:
;       Bx,Di,Bp,Ds,Es
; Calls:
;       None
; History:
;-----------------------------------------------------------------------;

;------------------------------Pseudo-Code------------------------------;
; {
; }
;-----------------------------------------------------------------------;
; The more complex case of blt'ing between 2 bitmaps, one of which lives
; in the local memory, the other of which lives on the board.

        align   4
cProc   SoftSrcSpecialist, <PUBLIC,NODATA,NEAR>, <edi,esi,ebx,edx,ebp>

        localW  x_src
        localW  y_src
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        localW  tempRows                ; working scan counter
        localW  CenterWords             ; # words in center of src blt
        localW  ncxExt                  ; cxExt adjust to src word boundaries
        localW  nxDst                   ; dest x origin adj to src word bdry's
        localW  BltFlags                ; local src to board blt flags
        localW  src_width               ; width of memory bitmap
cBegin

; use ebx as a pointer to the destination bitmap header
        mov     ebx, AIxfer.pbmhDest

; convert destination bitmap address to x and y for 8514 hardware
        memregread      eax,dest_map
        mov     x_dst,ax
        ror     eax,16
        mov     y_dst,ax
        calc8514xy  [ebx].bitmap_address
        add     x_dst,dx
        add     y_dst,ax

; set up the destination width and height
; use the clip rect set up in srcdestblt routine
        memregread      ax,dim1
        mov     total_width,ax
        memregread      ax,dim2
        mov     total_height,ax

; select the source bitmap map
        memregread      eax,src_map
        mov     x_src,ax
        ror     eax,16
        mov     y_src,ax

        WaitQIdle

; START OF CMVC 84887 - New Code
; Get the pixel op out and test horizontal blt direction.
        mov     edx, pixelop
        test    dl, OCT_DX_BIT
        jz      short blt_leftright

        WaitQ   2                       ; need room in the queue

        ;--------------------------------------------------------------
        ; Blt is in the right to left direction. Set MINX/MAXX scissor according to...
        ; Previously, we made the false assumption that all Blts were left to right!
        ;--------------------------------------------------------------
        mov     ax, x_dst           ; In this case the right most edge.
        sub     ax, total_width     ; Right edge - Blt width = Left edge.
        or      ax, XMIN_2DECODE
        outwQ   XMIN, ax

        mov     ax, x_dst           ; Now the Right edge.
        or      ax, XMAX_2DECODE
        outwQ   XMAX, ax
        jmp     short getbmp        ; Resume


blt_leftright:
; END OF CMVC 84887 - New Code

        WaitQ   2                       ; need room in the queue

        mov     ax,x_dst                ; set up scissor rectangle
        or      ax,XMIN_2DECODE
        outwQ   XMIN,ax

        mov     ax,x_dst
        add     ax,total_width          ; Calculate the right edge of the scissor rect.
        or      ax,XMAX_2DECODE
        outwQ   XMAX,ax

getbmp:                                 ; Now lets get the source bitmap pointer CMVC 84887

; use ebx as a pointer to the source bitmap header
        mov     ebx, AIxfer.pbmhSrc

; make src bits per pel decision here
        mov     al, byte ptr [ebx].hw_format
        and     al, BPP_MASK
        cmp     al, ONE_BPP
        jz      ss_is_mono

IFDEF  S3
        cmp     al, EIGHT_BPP
        jz      ss_is_8bpp

IFDEF   BPP24
        cmp     al, SIXTEEN_BPP
        jz      ss_is_16bpp

ss_is_24bpp:

        ; blah
        mov     dx,1                    ; 01b mask for rounding

        mov     di,total_width          ; actual width of blt
        inc     di                      ; 1-based width
        mov     ax,x_src                ; clipped src x origin
        add     di,ax                   ; last pixel in scan +1
        add     di,dx                   ; round end up to next word boundary
        not     dx                      ; form round down to word bdry mask
        and     di,dx                   ; end x on scan rounded down
        mov     bx,ax                   ; save original start x
        and     ax,dx                   ; start x on scan rounded down
        sub     bx,ax                   ; # pixels moved left for start x
        neg     bx                      ; moving left edge left
        add     bx,x_dst                ; move dest x over by that x_dst
        and     bx,XY_SIGNIFICANT       ; mask to just hw bits
        mov     nxDst,bx                ; save for src blt usage later

        sub     di,ax                   ; # pixels in adjusted scan
        mov     ax,di
        mov     dx,3
        mul     dx
        mov     CenterWords,ax
        dec     ax                      ; 0-based for hw
        mov     ncxExt,ax               ; padded cxExt

        movzx   eax,nxDst
        mov     dx,3
        mul     dx
        mov     nxDst,ax

        WaitQ   2                       ; need room in the queue
        mov     ax,x_dst                ; set up scissor rectangle
        mov     dx,3
        mul     dx
        mov     bx,ax
        or      ax,XMIN_2DECODE
        outwQ   XMIN,ax
        ; We need to include the whole pel here not just the first byte.
        mov     ax,total_width          ; we want the total width here
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
        add     ax,bx                   ; Calculate the right edge of the scissor rect.
        or      ax,XMAX_2DECODE
        outwQ   XMAX,ax


        WaitQ   8                       ; need room in the queue
        memregread      eax,Function_1
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_VAR         ; variable data mode
        outwQ   FUNCTION_1,ax
        memregread      eax,Function_0
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_VAR         ; variable data mode
        outwQ   FUNCTION_0,ax
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE); pattern always 1s
        outwQ   LY,total_height         ; 0-based height
        outwQ   Y0,y_dst                ; destination y origin
        outwQ   X0,nxDst                ; destination x origin
        outwQ   LX,ncxExt               ; 0-based width of blt
        outwQ   CMD_FLAGS,CMDCOL24      ; 24 bpp blt from memory

;------------------------------------------------------------------------------
; Color source, 24 bpp
;------------------------------------------------------------------------------

        ; get pointer to bitmap in esi
        mov     ebx,AIxfer.pbmhSrc
        movzx   eax,[ebx].bm_width      ; scansize in bytes
        mov     dx,3
        mul     dx
        mov     di,ax
        movzx   ecx,y_src               ; get y addr
        mul     ecx                     ; get offset
        movzx   ecx,x_src               ; get leading slop
        and     ecx,not 1               ; word align down
        mov     edx,ecx
        shl     ecx,1
        add     ecx,edx
        add     eax,ecx                 ; add it to offset
        ;and     eax,not 1               ; word align down
        mov     esi,[ebx]               ; get pointer to virtual memory
        add     esi,eax                 ; add offset into bitmap

        movzx   eax,di                  ; scansize in bytes
        mov     dx,COLOR_0_WAIT         ; variable data port
        mov     edi,esi                 ; save -> current src scanline
        mov     bx,total_height         ; 0-based height of blt
        inc     bx                      ; 1-based height

ss_24bpp_lp0:
        movzx   ecx,CenterWords
        rep outsb
        add     edi,eax                 ; advance to next scanline
        mov     esi,edi                 ; refresh src offset
        dec     bx                      ; 1 less row to blt
        jnz     ss_24bpp_lp0            ; for all rows...

        jmp     ss_done


ss_is_16bpp:

ENDIF

; @DMS update for 16bpp !!!
; We would like to have as fast a local color src to board dest blt as is
; possible. This means that we would like to pull pixels out of the src
; bitmap as words from word aligned boundaries (the best Intel architecture
; case, this may change to dwords in the 80386 world), and push the pixels
; to the 8514/A in byte mode (meaning 2 pixels / word output to the board).

        ; blah
        mov     cl,0                    ; assume 16bpp
        ;this is major change for 16bpp all the same except for the rep sto
        mov     dx,1                    ; 01b mask for rounding

        movzx   edi,total_width         ; actual width of blt
        inc     edi                     ; 1-based
        mov     ax,x_src                ; clipped src x origin
        add     di,ax                   ; last pixel in scan +1
        add     di,dx                   ; round end up to next word boundary
        not     dx                      ; form round down to word bdry mask
        and     di,dx                   ; end x on scan rounded down
        mov     bx,ax                   ; save original start x
        and     ax,dx                   ; start x on scan rounded down
        sub     bx,ax                   ; # pixels moved left for start x
        neg     bx                      ; moving left edge left
        add     bx,x_dst                ; move dest x over by that amt
        and     bx,XY_SIGNIFICANT       ; mask to just hw bits
        mov     nxDst,bx                ; save for src blt usage later
        sub     di,ax                   ; # pixels in adjusted scan
        shr     di,cl                   ; # whole words total
        mov     CenterWords,di

        shl     di,cl                   ; new cxExt
        dec     edi                     ; 0-based for hw
        mov     ncxExt,di               ; padded cxExt


        WaitQ   8                       ; need room in the queue
        memregread      eax,Function_1
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_VAR         ; variable data mode
        outwQ   FUNCTION_1,ax
        memregread      eax,Function_0
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_VAR         ; variable data mode
        outwQ   FUNCTION_0,ax
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE); pattern always 1s
        outwQ   LY,total_height         ; 0-based height
        outwQ   Y0,y_dst                ; destination y origin
        outwQ   X0,nxDst                ; destination x origin
        outwQ   LX,ncxExt               ; 0-based width of blt
        outwQ   CMD_FLAGS,CMDCOL48      ; 4/8 bpp blt from memory

;------------------------------------------------------------------------------
; Color source, 16 bpp
;------------------------------------------------------------------------------

        ; get pointer to bitmap in esi
        mov     ebx,AIxfer.pbmhSrc
        movzx   ecx,[ebx].bm_width      ; scansize in bytes
        movzx   eax,y_src               ; get y addr
        mul     ecx                     ; get offset
        movzx   edx,x_src               ; get leading slop
        add     eax,edx                 ; add it to offset
        mov     esi,[ebx]               ; get pointer to virtual memory
        and     eax,not 1               ; word align down
        add     esi,eax                 ; add offset into bitmap

        mov     dx,COLOR_0_WAIT         ; variable data port
        mov     edi,esi                 ; save -> current src scanline
        movzx   eax,[ebx].bm_width      ; scansize in bytes
        add     eax,eax
        mov     bx,total_height         ; 0-based height of blt
        inc     bx                      ; 1-based height

ss_16bpp_lp0:
        movzx   ecx,CenterWords
@@:     push    eax
        lodsw
        ror     ax,8
        out     dx,ax
        pop     eax
        loop    @b

        add     edi,eax                 ; advance to next scanline
        mov     esi,edi                 ; refresh src offset
        dec     bx                      ; 1 less row to blt
        jnz     ss_16bpp_lp0            ; for all rows...

        jmp     ss_done

ss_is_8bpp:
ENDIF

; We would like to have as fast a local color src to board dest blt as is
; possible. This means that we would like to pull pixels out of the src
; bitmap as words from word aligned boundaries (the best Intel architecture
; case, this may change to dwords in the 80386 world), and push the pixels
; to the 8514/A in byte mode (meaning 2 pixels / word output to the board).

        ; blah
        mov     cl,1                    ; assume 8 bpp, 2 bytes/word
        mov     dx,1                    ; 01b mask for rounding

        movzx   edi,total_width         ; actual width of blt
        inc     edi                     ; 1-based
        mov     ax,x_src                ; clipped src x origin
        add     di,ax                   ; last pixel in scan +1
        add     di,dx                   ; round end up to next word boundary
        not     dx                      ; form round down to word bdry mask
        and     di,dx                   ; end x on scan rounded down
        mov     bx,ax                   ; save original start x
        and     ax,dx                   ; start x on scan rounded down
        sub     bx,ax                   ; # pixels moved left for start x
        neg     bx                      ; moving left edge left
        add     bx,x_dst                ; move dest x over by that amt
        and     bx,XY_SIGNIFICANT       ; mask to just hw bits
        mov     nxDst,bx                ; save for src blt usage later
        sub     di,ax                   ; # pixels in adjusted scan
        shr     di,cl                   ; # whole words total
        mov     CenterWords,di

        shl     di,cl                   ; new cxExt
        dec     edi                     ; 0-based for hw
        mov     ncxExt,di               ; padded cxExt

        WaitQ   8                       ; need room in the queue
        memregread      eax,Function_1
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_VAR         ; variable data mode
        outwQ   FUNCTION_1,ax
        memregread      eax,Function_0
        and     ax,ROP2_FIELD           ; isolate mix mode
        or      ax,FUNC_2OP_VAR         ; variable data mode
        outwQ   FUNCTION_0,ax
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES+MD_UP_FALSE); pattern always 1s
        outwQ   LY,total_height         ; 0-based height
        outwQ   Y0,y_dst                ; destination y origin
        outwQ   X0,nxDst                ; destination x origin
        outwQ   LX,ncxExt               ; 0-based width of blt

        outwQ   CMD_FLAGS,CMDCOL48      ; 4/8 bpp blt left to right from memory

;------------------------------------------------------------------------------
; Color source, 8 bpp
;------------------------------------------------------------------------------
        ; get pointer to bitmap in esi
        mov     ebx,AIxfer.pbmhSrc
        movzx   ecx,[ebx].bm_width      ; scansize in bytes
        movzx   eax,y_src               ; get y addr
        mul     ecx                     ; get offset
        movzx   edx,x_src               ; get leading slop
        add     eax,edx                 ; add it to offset
        mov     esi,[ebx]               ; get pointer to virtual memory
        and     eax,not 1               ; word align down
        add     esi,eax                 ; add offset into bitmap

        mov     dx,COLOR_0_WAIT         ; variable data port
        mov     edi,esi                 ; save -> current src scanline
        movzx   eax,[ebx].bm_width      ; scansize in bytes
        mov     bx,total_height         ; 0-based height of blt
        inc     bx                      ; 1-based height

ss_8bpp_lp0:
        movzx   ecx,CenterWords

        IFNDEF  MEMMAPIO
    rep outsw
        ELSE
        push    edi
        ; @DMS we do not go more than 64k here as long as the PHUNK size
        ;      remains 64k !!!
        mov     edi,pVRAM
    rep movsw
        pop     edi
        ENDIF

        add     edi,eax                 ; advance to next scanline
        mov     esi,edi                 ; refresh src offset
        dec     bx                      ; 1 less row to blt
        jnz     ss_8bpp_lp0             ; for all rows...

        jmp     ss_done

;------------------------------------------------------------------------------
; Mono source
;------------------------------------------------------------------------------

ss_is_mono:

IFDEF   BPP24
        test    [_DDT],USE_24BPP
        jz      ss_mono_not_24

        mov     ebx,AIxfer.pbmhSrc
        movzx   edi,[ebx].bm_width      ; scansize in pels
        add     edi,7                   ; round up to byte boundry
        shr     edi,3                   ; get byte count
        movzx   eax,y_src               ; src y origin
        mul     edi                     ; offset to scan of interest
        mov     esi,[ebx]               ; get pointer to virtual memory
        add     esi,eax                 ; add offset into bitmap

; Calculate the number of pels into the first byte we have to
; go before we start (i.e. do we have a non byte-aligned source). #74143
        mov     ax,x_src                ; pixels into scanline
        and     ax,7
        push    ax                      ; StartBits for Copy24MonoMixToVRAM

        movzx   eax,x_src               ; pixels into scanline
        shr     eax,3                   ; get byte count
        add     esi,eax                 ; -> byte containing pixel

        push    ONE_BPP
        movzx   eax,total_height        ; get zero based mono height
        push    eax
        movzx   eax,word ptr [ebx].hw_width
        push    eax
        movzx   edx,total_width         ; get blt width in pels
        push    edx

        mov     ax,x_dst
        ror     eax,16
        mov     ax,y_dst
        push    eax
        push    esi
        call    _Copy24MonoMixToVRAM
        add     esp,26

        jmp     ss_done
ss_mono_not_24:
ENDIF


;----------------------------------------------------------------------------
; non-24 bit mono source
;----------------------------------------------------------------------------

PURGE_PIPELINE  equ 1
ODDBYTE         equ 2
PREFETCH        equ 4

        ; calculate phase shift
        mov     cx, x_dst               ; target pel
        mov     bx, cx                  ; save it
        and     cx, 7                   ; bit # in destination byte
        mov     ax, x_src               ; source pel
        and     ax, 7                   ; bit # in source byte
        sub     cx, ax                  ; get right shift count
        jnz     short @F
        jmp     ss_mono_equal_align
@@:
        ; get new destination
        mov     ax, bx                  ; target pel
        and     ax, XY_SIGNIFICANT AND NOT 7
        mov     nxDst, ax               ; byte aligned destination

        ; calculate output size
        mov     dx, total_width         ; 0-based width in pels
        add     bx, dx                  ; offset of last pel
        sub     bx, ax                  ; less offset of nxDst
        shr     bx, 4                   ; get 0-based word count
        inc     bx                      ; 1-based word count

        ; calculate total bytes to read
        mov     ax, x_src
        add     dx, ax                  ; offset of last pel
        and     dx, NOT 7
        shr     dx, 3                   ; 0-based offset of last byte
        and     ax, NOT 7
        shr     ax, 3                   ; 0-based offset of first byte
        sub     dx, ax                  ; 0-based byte count
        inc     dx                      ; 1-based byte count

        ; set blt flags
        mov     BltFlags, 0             ; clear flags
        or      cl, cl                  ; negative shift?
        jns     short @F
        or      BltFlags, PREFETCH
        dec     dx
@@:
        test    dx, 1                   ; odd # of bytes?
        jz      short @F
        or      BltFlags, ODDBYTE
@@:
        shr     dx, 1
        cmp     dx, bx                  ; matching word count?
        jz      short @F
        or      BltFlags, PURGE_PIPELINE
@@:
        ; set widths for input and output
        mov     CenterWords, dx
        shl     bx, 4                   ; 1-based pel count
        dec     bx                      ; 0-based pel count
        mov     ncxExt, bx              ; save 0-based pel output count

        ; H/W initializations common to all mono to board cases.
        WaitQ   8                       ; need room in the queue
        memregread      eax,Function_0
        and     al,ROP2_FIELD           ; isolate mix mode
        or      al,FUNC_2OP_COL0        ; variable data mode
        outwQ   FUNCTION_0,ax
        memregread      eax,Function_1
        and     al,ROP2_FIELD           ; isolate mix mode
        or      al,FUNC_2OP_COL1        ; variable data mode
        outwQ   FUNCTION_1,ax
        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE); variable pattern
        outwQ   LX,ncxExt               ; 0-based width of blt
        outwQ   LY,total_height
        inc     ax                      ; make height (still in ax) 1 based
        mov     tempRows,ax             ; working counter storage
        outwQ   Y0,y_dst                ; destination y origin
        outwQ   X0,nxDst                ; destination x origin
        outwQ   CMD_FLAGS,CMDMONO       ; 1 bpp blt from memory

        ; get pointer to bitmap in esi
        mov     ebx,AIxfer.pbmhSrc
        movzx   edi,[ebx].bm_width      ; scansize in pels
        add     edi,7                   ; round up to byte boundary
        and     edi,NOT 7
        shr     edi,3                   ; get byte count
        mov     src_width,di            ; save the width
        movzx   eax,y_src               ; src y origin
        mul     edi                     ; offset to scan of interest
        mov     esi,[ebx]               ; get pointer to virtual memory
        add     esi,eax                 ; add offset into bitmap
        movzx   eax,x_src               ; pixels into scanline
        shr     ax, 3                   ; make byte offset
        add     esi,eax                 ; -> byte containing pixel

        mov     dx, COLOR_0_WAIT        ; variable data port

        ; use phase difference to calculate the mask needed for
        ; preserving bits to be pipelined to the next operation.
        mov     ch, 0FFh                ; for creating mask
        and     cl, 7                   ; phase shift MOD 8
        shr     ch, cl                  ; 0s to high end,this is the ror mask

ss_mono_nextscan:
        push    esi                     ; save scan start offset
        mov     bh, 0                   ; clear initial bits (not needed)

        ; save initial bits directly into BH
        test    BltFlags, PREFETCH      ; need to prefetch a nibble?
        jz      short @F                ; if not, continue
        lodsb                           ; get first byte
        ror     ax, cl                  ; shift rightmost bits into AH
        SavePhaseBits ah, bh
@@:
        mov     di,CenterWords          ; # src words to be fetched
        shr     di,1                    ; Preserve the odd word count
        jz      short ss_mono_no_dword
@@:
        lodsd                           ; fetch P2|P3|P0|P1:P2|P3|P0|P1
                                        ; about to process what's at the
                                        ; low-word first.
        DoPhaseShift                    ; phase shift and output AX
        SendBits16                      ; send out AX

        ror     eax,16                  ; move the hi-word down to low-word
                                        ; about to process what was the hi-word
        DoPhaseShift                    ; phase shift and output AX
        SendBits16                      ; send out AX

        dec     di                      ; drop word count
        jnz     short @B                ; for all whole src words to output...

ss_mono_no_dword:

        mov ax,0                        ; Cleanup AX for the remaining unused
                                        ; bits. jsj - CMVC 82606.
        mov     di,CenterWords          ; # src words to be fetched
        and     di,1                    ; The fetch for the odd word if any
        jz      short @F

        lodsw
        DoPhaseShift                    ; phase shift and output AX
        SendBits16                      ; send out AX
        mov ah,0                        ; Cleanup AH for the remaining unused
                                        ; bits.  jsj - CMVC 82606.
@@:
        ; handle odd byte case (also does PURGE_PIPELINE function)
        test    BltFlags, ODDBYTE
        jz      short @F
        mov     al, [esi]               ; get next byte
        DoPhaseShift                    ; phase shift and output AX
        SendBits16                      ; send out AX
        jmp     short ss_mono_next
@@:
        ; output pipelined nibble, ignoring rest of word output.
        test    BltFlags,PURGE_PIPELINE
        jz      short ss_mono_next


        GetPhaseBits al, bh
        ; for 8514, an additional out is needed for alignment.
        ; AL contains the last byte of data.  Don't forget to
        ; massage the data into position for the 8514/A pixel
        ; data transfer register!  82606 Juan Sierra.
        IFNDEF S3
        ror     ax,4                    ; CMVC 82606
        ror     ah,4                    ; CMVC 82606
        rol     ax,1                    ; CMVC 82606
        out     dx,ax                   ; output pipelined nibble
        ENDIF
        out     dx,ax

ss_mono_next:
        pop     esi                     ; recover original src offset
        movzx   eax,src_width           ; get total number of bytes
        add     esi,eax                 ; go to next source scan

        dec     tempRows                ; 1 less row to blt
        jnz     ss_mono_nextscan        ; else for all rows to blt...
        jmp     ss_done                 ; get out if no more...

;------------------------------------------------------------------------------
; Mono src, src and destination nibble alignments are equal.
;------------------------------------------------------------------------------

ss_mono_equal_align:

        mov     dx,total_width          ; width of blt in pixels
        inc     dx

        mov     ax,x_src                ; src left edge x
        mov     bx,ax                   ; need it later also
        and     ax,15                   ; bit position in src word
        add     ax,cx                   ; adjust for right phase shift
        neg     ax                      ; # pixels to adjust dest x by
        add     ax,x_dst                ; dest adj. for src word fetches
        and     ax,XY_SIGNIFICANT       ; mask to just hw bits
        mov     nxDst,ax                ; save new left x for bottom level

        mov     ax,bx                   ; src left edge x
        add     ax,dx                   ; point to right edge x + 1
        and     bx,Not 15               ; src left rounded down to word bdry
        sub     ax,bx                   ; # pixels in extended scan
        mov     di,ax                   ; need this later
        add     ax,15                   ; round up to word boundary
        shr     ax,4                    ; now # whole src words to fetch
        mov     CenterWords,ax          ; save for bottom level

        mov     ax,di                   ; # pixels in extended scan
        add     ax,cx                   ; adjust extent by phase shift
        add     ax,15                   ; round up to word boundary
        and     ax,Not 15               ; now # pixels in adj extent
        dec     ax                      ; 0-based for hw
        mov     ncxExt,ax               ; save for bottom level

        inc     ax                      ; back to 1-based new x extent
        shr     ax,4                    ; # words in extent
        mov     BltFlags,0
        cmp     ax,CenterWords          ; equal to src word fetches ?
        jbe     short @F                ; yes, no pipelined pixels...
        or      BltFlags,PURGE_PIPELINE ; have to write pipelined pixels
@@:

        ; H/W initializations common to all mono to board cases.
        WaitQ   8                       ; need room in the queue
        memregread      eax,Function_0
        and     al,ROP2_FIELD           ; isolate mix mode
        or      al,FUNC_2OP_COL0        ; variable data mode
        outwQ   FUNCTION_0,ax
        memregread      eax,Function_1
        and     al,ROP2_FIELD           ; isolate mix mode
        or      al,FUNC_2OP_COL1        ; variable data mode
        outwQ   FUNCTION_1,ax
        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE); variable pattern
        outwQ   LX,ncxExt               ; 0-based width of blt
        outwQ   LY,total_height
        inc     ax                      ; make height (still in ax) 1 based
        mov     tempRows,ax             ; working counter storage
        outwQ   Y0,y_dst                ; destination y origin
        outwQ   X0,nxDst                ; destination x origin
        outwQ   CMD_FLAGS,CMDMONO       ; 1 bpp blt from memory

        ; get pointer to bitmap in esi
        mov     ebx,AIxfer.pbmhSrc
        movzx   edi,[ebx].bm_width      ; scansize in pels
        add     edi,7                   ; round up to byte boundry
        and     edi,not 7
        shr     edi,3                   ; get byte count
        mov     src_width,di            ; save the width
        movzx   eax,y_src               ; src y origin
        mul     edi                     ; offset to scan of interest
        mov     esi,[ebx]               ; get pointer to virtual memory
        add     esi,eax                 ; add offset into bitmap
        movzx   eax,x_src               ; pixels into scanline
        mov     cx,(1 Shl  8) + 4       ; shift count for xyaddr
        shr     ax,cl
        xchg    ch,cl                   ; round to specified boundary
        shl     ax,cl                   ; now make byte offset
        add     esi,eax                 ; -> byte containing pixel

        mov     dx,COLOR_0_WAIT         ; variable data port
        mov     bx,tempRows

ss_mono_eqScan_lp:

        IFNDEF  MEMMAPIO
        mov     edi,esi                 ; save scan offset
        ELSE
        mov     edx,esi                 ; wont be using dx in twistbits
        ; @DMS can we go over  64k here
        mov     edi,pVRAM
        ENDIF
        movzx   ecx,CenterWords         ; # whole src words to fetch
        shr     cx,1
        jz      short ss_mono_eqno_dword


@@:
        ; @DMS can do this faster with a dword load instead of two word loads
        twistbits16
        twistbits16

        loop    @B                      ; for all whole src words to output...

ss_mono_eqno_dword:
        movzx   ecx,CenterWords
        and     cx,1                    ; the last fetch for the odd word
        jz      short @F

        twistbits16
@@:

        IFNDEF  MEMMAPIO
        mov     esi,edi                 ; recover original src offset
        ELSE
        mov     esi,edx                 ; recover original src offset
        ENDIF
        movzx   eax,src_width           ; get total number of bytes
        add     esi,eax                 ; go to next source scan

        dec     Bx                      ; 1 less row to blt
        jnz     Short ss_mono_eqScan_lp ; else for all rows to blt...

ss_done:

        SetNoXClip

cEnd

ENDIF ;HARD_DRAW

ENDIF ;_8514

;***********************************************************************
;
; Function: PatDestBlt
;
; Called by: eddb_bitblt in eddnbblt.c
;
; Purpose: carries out a bitblt operation for a pattern and destination
; rop.
; Assumes the calling function has not made the call until the hardware
; is free
;
;***********************************************************************


        align   4
PatDestBlt  proc near

        push    esi
        push    edi
        push    ebx
        push    ebp
        IFNDEF  _8514
        pushxga

; get the base address of the hardware registers
        movxga  pXGARegs
        ELSE
        mov     esi,p8514Regs
        ENDIF

; use ebx as a pointer to the destination bitmap header
        mov             ebx, AIxfer.pbmhDest

; use edi to count the number of clip regions
        movzx           edi, word ptr AIxfer.cDestClipRects

; select the destination map
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

; write destination bitmap address to hardware mapA base
        mov             eax, [ebx].bitmap_address
        IFDEF  _8514
        IFDEF  HARD_DRAW
        and     eax,0fffffffh   ; clear the vram marker
        ENDIF
        ENDIF
        memregwrite     pi_map_base_ptr_A, eax

; write mapA width and height from bitmap header
        mov             eax, dword ptr [ebx].hw_width
        memregwrite     pi_map_size_A, eax

; write mapA format from bitmap header
        mov             al, byte ptr [ebx].hw_format
        memregwrite     pi_map_format_A, al

; use ebx as a pointer to the pattern bitmap header
; - which will be found in the same place as the source bm header
        mov             ebx, AIxfer.pbmhSrc

; select the pattern map
; this is always pixel map B although the pixelop may define this to be
; the pattern map (if we are not dithering) or the source map (if we are)
; The distinction is transparent to this function
        memregwrite     pi_map_index_B, SEL_PIX_MAP_B

; write mapB format from the parameter block
        mov             al, byte ptr [ebx].hw_format
        memregwrite     pi_map_format_B,  al


; write pattern bitmap address to hardware mapB base
        mov             eax, [ebx].bitmap_address
        IFDEF  _8514
        IFDEF  HARD_DRAW
        and     eax,0fffffffh   ; clear the vram marker
        ENDIF
        ENDIF
        memregwrite     pi_map_base_ptr_B, eax

; write mapB width and height from bitmap header
        mov             eax, dword ptr [ebx].hw_width
        memregwrite     pi_map_size_B, eax

; use ebp to reference the clip rectangles
        mov     ebp, dword ptr AIxfer.pNextDestClipRect
        jmp             short patdest_decclip

patdest_writepixop:
; write the pixel op to kick off the blt
        mov             eax, pixelop
        memregwrite     pixel_op, eax

IFDEF HARD_DRAW
IFDEF   _8514
; make src bits per pel decision here
        mov     al, byte ptr [ebx].hw_format
        ; mask to keep just the BPP information (ie ignore intel/motorola bit)
        and     al, BPP_MASK
        cmp     al, ONE_BPP
        jz      short pat_1BPP

pat_8BPP:
        push    edi
        lea     edi,dword ptr PatDestBltColor
        jmp     short patdest_doit

pat_1BPP:
        push    edi
        lea     edi,dword ptr _PatDestBlt1To8
;       jmp     short patdest_doit

patdest_doit:
        call    edi
        pop     edi
ENDIF   ;_8514

ELSE
; write the pixel op to kick off the blt
        saveregs
        call    _eddf_MESS
        restoreregs
ENDIF

patdest_no_intersect:
; exit now if no more clip regions, otherwise go and clip to the next
        or      edi, edi
        jnz     short patdest_nextclip
        IFNDEF  _8514
        popxga
        ENDIF
patdest_exit:
        pop     ebp
        pop     ebx
        pop     edi
        pop     esi
        ret

patdest_nextclip:
; advance the global pointer to the clip rectangles
        add     ebp, len_clip_rect


patdest_decclip:
; decrement the clip region counter
        dec     edi

patdest_doclipping:

; clip the destination to the next clip region - using the hardware
; scissor is too slow as it 'draws' the area outside the clip but
; without updating the screen

; for a pattern and destination blt the blt direction is always left to
; right, top to bottom so the target coordinates are correctly ordered
; in the parameter block

; find the maximum of the clip bottom edge and the destination
; bottom edge and save in eax high word
        max             [ebp].clip_y0, AIxfer.Dest0Coord.y, ax
        mov             cx, ax
        shl             eax, 10h

; calculate the pattern origin y coordinate (y bias) and store in edx high
; word.  See single clip case above for explanation of the pattern origin
; set up. This is (dest coord - origin coord) % pattern height and, if
; the result is negative it has the width added.
;----------------------------------------------------------------------
; CMVC 80935
;
; S3 Pattern Tiling -- WARNING!!!
; When determining how much to bias the pattern, we must adjust BOTH
; the X and Y destination coordinates down to the nearest multiple of 8.
; The S3 pattern tile command WILL NOT align our pattern with the upper
; left-hand corner of the destination.  Instead, it will ignore the low
; order 3 bits of both the destination X and Y coordinates and apply
; the pattern repeatedly until the destination area is full.  As long
; as we know about this (undocumented) behavior, we can successfully
; bias our patterns.
;----------------------------------------------------------------------
        mov             ax, cx
 ifdef S3                                       ; CMVC 80935
        and             ax,0FFF8h               ; CMVC 80935
 endif                                          ; CMVC 80935
        sub             ax, AIxfer.PatOrig.y

        cwd
        idiv            word ptr [ebx].bm_height

;EKF    test            dx, 1000h         ; test the sign bit
        test            dx, 8000h         ; test the sign bit
        jz              short @F
        add             dx, word ptr [ebx].bm_height
@@:     shl             edx, 16

; find the minimum of the distances from the bottom edge (in cx) to the
; bottom edge of the bitmap and bottom edge of the target: put the
; value in ecx high word
        mov             ax, cx
        sub             ax, [ebp].clip_y1
        ja              patdest_no_intersect
        sub             cx, AIxfer.Dest1Coord.y
        ja              patdest_no_intersect
        rmax            cx, ax
        neg             cx
        shl             ecx, 10h

; find the maximum of the clip left edge and the destination left edge
; and save on the stack for now to avoid waiting for the hardware until
; later
        max             [ebp].clip_x0, AIxfer.Dest0Coord.x, ax
        mov             cx, ax
        push            eax

; calculate the pattern origin x coordinate and store in the pattern
; x address register: origin is
; ax contains the max of the clip left edge and the destination x0
 ifdef S3                                       ; CMVC 80935
        and             ax,0FFF8h               ; CMVC 80935
 endif                                          ; CMVC 80935
        sub             ax, AIxfer.PatOrig.x

        cwd
        idiv            word ptr [ebx].bm_width
;EKF    test            dx, 1000h         ; test the sign bit
        test            dx, 8000h         ; test the sign bit
        jz              short @F
        add             dx, word ptr [ebx].bm_width

@@:
; find the minimum of the distances from the left edge (in ax) to the
; right edge of the bitmap and right edge of the target: put the value
; in the dimension registers along with the height in ecx high word
; if there is no intersection with the clip rectangle then tidy up the
; stack (removing the destination coordinates) and go and see if there
; is another clip rectangle
        mov             ax, cx
        sub             ax, [ebp].clip_x1
        jbe             short @F
        add             esp, 4
        jmp             patdest_no_intersect
@@:     sub             cx, AIxfer.Dest1Coord.x
        jbe             short @F
        add             esp, 4
        jmp             patdest_no_intersect
@@:     rmax            cx, ax
        neg             cx
        IFNDEF          _8514
        waitshort
        ENDIF
        memregwrite     dimensions, ecx

; the destination coordinates are currently on the stack - pop them off into
; the dest map coordinate registers
        pop     eax
        memregwrite     dest_map, eax

; dithered patterns are done as a source to dest blt, non dithered as
; pattern to dest: we don't know which is being done here so write the
; pattern coordinates to both pattern and source coordinate registers
        memregwrite     src_map, edx
        memregwrite     patt_map, edx
        jmp             patdest_writepixop


PatDestBlt         endp

IFDEF _8514
;***********************************************************************
;
; Function: PatDestBltColor
;
; Called by: PatDestBlt
;
; Purpose: Takes the color bitmap and uses it as a pattern for a fill.
;          The format of the pattern is our internal format.
;
; On Entry:
;       ESI contains pointer to shadowregs
;
;***********************************************************************
IFDEF   HARD_DRAW

        align   4
cProc   PatDestBltColor, <PUBLIC,NODATA,NEAR>, <edi ,esi, ebx, edx, ebp>

        localW  x_src
        localW  y_src
        localW  x_dst
        localW  y_dst
        localW  patt_orig_x
        localW  patt_orig_y
        localW  patt_width
        localW  patt_height
        localW  total_width
        localW  total_height
        localD  pVRAMpat
        localW  XBias
        localW  YBias
        localB  fFastBlt
cBegin
        mov     ebx,_pCacheMap
        mov     eax,[ebx].cm_color_dither
        mov     pVRAMpat,eax
        calc8514xy  eax
        mov     x_src,dx
        mov     y_src,ax


        ;--------------------------------------------------------------
        ; use ebx as a pointer to the destination bitmap header
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhDest

        ;--------------------------------------------------------------
        ; convert destination bitmap address to x and y for 8514 hardware
        ;--------------------------------------------------------------
        memregread      eax,dest_map
        mov     x_dst,ax
        ror     eax,16
        mov     y_dst,ax
        calc8514xy  [ebx].bitmap_address
        add     x_dst,dx
        add     y_dst,ax

        ;--------------------------------------------------------------
        ; set up the destination width and height
        ; pick up clipping from patdestblt routine
        ;--------------------------------------------------------------
        memregread      ax,dim1
        mov     total_width,ax

        memregread      ax,dim2
        mov     total_height,ax

        ;--------------------------------------------------------------
        ; use ebx as a pointer to the pattern bitmap header
        ; - which will be found in the same place as the source bm header
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhSrc

        mov     ax,[ebx].bm_width
        mov     patt_width,ax

        mov     ax,[ebx].bm_height
        mov     patt_height,ax

        ;--------------------------------------------------------------
        ; Calculate the X and Y pattern bias values.  The formulas used
        ; are as follows:
        ; 
        ;       XBias = ( Dx - Px ) & ( Pattern Width - 1 )
        ;       YBias = ( Dy - Py ) & ( Pattern Height - 1 )
        ; 
        ; where Dx = Destination X Address
        ;       Dy = Destination Y Address
        ;       Px = Pattern Origin X Address
        ;       Py = Pattern Origin Y Address
        ; 
        ; NOTE: Both the pattern width and height must be a multiple
        ;       of 2.
        ; 
        ; Previous warning about the dangers of Y-biasing can now be
        ; ignored since we're fetching the pattern origin from the
        ; right place now.
        ;--------------------------------------------------------------

        mov     ax,y_dst
        sub     ax,AIxfer.PatOrig.y
        and     ax,[ebx].hw_height
        mov     YBias,ax

        mov     ax,x_dst
        sub     ax,AIxfer.PatOrig.x
        and     ax,[ebx].hw_width

        ;--------------------------------------------------------------
        ; Before we save our x bias value, we must compensate for the
        ; number of bytes per pel in each pixel depth.  We also calculate
        ; the width of the pattern bitmap in bytes.
        ;--------------------------------------------------------------
        mov     cx,patt_width
        mov     dx,[ebx].hw_format
        and     dx,BPP_MASK

        cmp     dl,TWENTYFOUR_BPP
        jnz     @F
        fast3x  ax,dx
        fast3x  cx,dx

        push    ebx                     ;Save it!

        ;--------------------------------------------------------------
        ; For 24bpp, ALL of our X-related values must be tripled thanks
        ; to the hokey way the S3 must be configured for that mode.
        ;--------------------------------------------------------------
        mov     bx,x_dst
        fast3x  bx,dx
        mov     x_dst,bx

        mov     bx,x_src
        fast3x  bx,dx
        mov     x_src,bx

        mov     bx,total_width
        inc     bx
        fast3x  bx,dx
        dec     bx
        mov     total_width,bx

        pop     ebx                     ;Restore it!

        jmp     short XBias_done
@@:
        cmp     dl,SIXTEEN_BPP
        jnz     short XBias_done
        shl     ax,1
        shl     cx,1

XBias_done:
        mov     XBias,ax
        mov     patt_width,cx

        ;--------------------------------------------------------------
        ; Load the source pointer to the pattern bitmap.  If both the
        ; XBias and YBias values are zero, no biasing is necessary.
        ; However, if biasing is necessary, we will create a biased
        ; version of the bitmap in the PHUNK.
        ;--------------------------------------------------------------
        push    esi
        mov     esi,[ebx].virt_addr
        mov     edi,esi
        or      ax,YBias
        jz      biasing_done

        ;--------------------------------------------------------------
        ; Biasing is needed.  EDI will point to the PHUNK.  Our transfer
        ; is done in two major loops:
        ; 
        ; first_y_loop:
        ;       for ( y = YBias; y < pattern height; y++)
        ;       {
        ;           for ( x = XBias; x < pattern width; x++)
        ;               pPHUNK++ = source(x,y);
        ; 
        ;           for ( x = 0; x < XBias; x++)
        ;               pPHUNK++ = source(x,y);
        ;       }
        ; 
        ; second_y_loop:
        ;       for ( y = 0; y < YBias; y++)
        ;       {
        ;            /* Same as previous loop */
        ;       }
        ; 
        ;--------------------------------------------------------------
        cld
        mov     edi,_pPhunkVirt
        add     edi,08000h
        push    edi
        mov     cx,[ebx].bm_height
        sub     cx,YBias
        mov     bx,YBias

first_Y_loop:
        ;--------------------------------------------------------------
        ; BX  = Current row offset into the pattern bitmap
        ; CX  = # of Rows to do Y-biasing.
        ; ESI - pointer to the beginning of the pattern bitmap.
        ;--------------------------------------------------------------
        push    cx
        push    esi

        ;--------------------------------------------------------------
        ; Calculate the byte offset into the bitmap for the beginning
        ; of our row and save it.
        ;--------------------------------------------------------------
        movzx   eax,bx
        mul     patt_width
        push    eax

        ;--------------------------------------------------------------
        ; The first half of the row processing starts at the XBias
        ; offset and continues until the end of the row.  Load up
        ; ESI with the final address where our copy will start.
        ; Also, calculate the number of bytes to move in the first half.
        ;--------------------------------------------------------------
        add     ax,XBias
        add     esi,eax
        movzx   ecx,patt_width
        sub     cx,XBias
        repe    movsb

        ;--------------------------------------------------------------
        ; Restore EAX = The offset to the beginning of the current row.
        ; Restore ESI = Pointer to the beginning of the pattern bitmap.
        ;--------------------------------------------------------------
        pop     eax
        pop     esi
        push    esi

        ;--------------------------------------------------------------
        ; Generate the final address to the beginning of this row and
        ; prepare to finish off this row by copying from the beginning
        ; to the XBias offset.  Note: if XBias is 0, the work for this
        ; row is complete.
        ;--------------------------------------------------------------
        add     esi,eax
        mov     cx,XBias
        jcxz    @F
        repe    movsb
@@:
        ;--------------------------------------------------------------
        ; Restore CX  = # of Rows to do Y-biasing.
        ; Restore ESI = Pointer to the beginning of the pattern bitmap.
        ; Incrememnt BX for the next row.
        ;--------------------------------------------------------------
        pop     esi
        pop     cx
        inc     bx
        loop    first_Y_loop

        ;--------------------------------------------------------------
        ; The second Y loop start from the first row in the bitmap
        ; and proceeds until the row before the YBias row.  However,
        ; if YBias is zero, our work is done.
        ;--------------------------------------------------------------
        xor     bx,bx
        movzx   ecx,YBias
        jcxz    no_Y_biasing

second_Y_loop:
        ;--------------------------------------------------------------
        ; BX  = Current row offset into the pattern bitmap
        ; CX  = # of Rows to do Y-biasing.
        ; ESI - pointer to the beginning of the pattern bitmap.
        ;--------------------------------------------------------------
        push    cx
        push    esi

        ;--------------------------------------------------------------
        ; Calculate the byte offset into the bitmap for the beginning
        ; of our row and save it.
        ;--------------------------------------------------------------
        movzx   eax,bx
        mul     patt_width
        push    eax

        ;--------------------------------------------------------------
        ; The first half of the row processing starts at the XBias
        ; offset and continues until the end of the row.  Load up
        ; ESI with the final address where our copy will start.
        ; Also, calculate the number of bytes to move in the first half.
        ;--------------------------------------------------------------
        add     ax,XBias
        add     esi,eax
        movzx   ecx,patt_width
        sub     cx,XBias
        repe    movsb

        ;--------------------------------------------------------------
        ; Restore EAX = The offset to the beginning of the current row.
        ; Restore ESI = Pointer to the beginning of the pattern bitmap.
        ;--------------------------------------------------------------
        pop     eax
        pop     esi
        push    esi

        ;--------------------------------------------------------------
        ; Generate the final address to the beginning of this row and
        ; prepare to finish off this row by copying from the beginning
        ; to the XBias offset.  Note: if XBias is 0, the work for this
        ; row is complete.
        ;--------------------------------------------------------------
        add     esi,eax
        movzx   ecx,XBias
        jcxz    @F
        repe    movsb
@@:
        ;--------------------------------------------------------------
        ; Restore CX  = # of Rows to do X-biasing.
        ; Restore ESI = Pointer to the beginning of the pattern bitmap.
        ; Incrememnt BX for the next row.
        ;--------------------------------------------------------------
        pop     esi
        pop     cx
        inc     bx
        loop    second_Y_loop

no_Y_biasing:
        pop     edi

biasing_done:
        ;--------------------------------------------------------------
        ; Restore pointer to shadow regs.
        ;--------------------------------------------------------------
        pop     esi

        ;--------------------------------------------------------------
        ; Take the new biased pattern bitmap and cache it in the color
        ; pattern area.
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhSrc
        movzx   eax,WORD PTR [ebx].hw_format
        push    eax
        movzx   eax,WORD PTR [ebx].hw_height
        push    eax
        movzx   eax,WORD PTR [ebx].hw_width
        push    eax
        mov     eax,pVRAMpat
        push    eax
        push    edi
        call    _CopyMemoryToVRAM
        add     esp,20

        ;--------------------------------------------------------------
        ; Now that the pattern bitmap is cached, we want to deal with
        ; pels instead of bytes again.  Remember: for 24bpp, we must
        ; deal in physical pels, not logical pels.
        ;--------------------------------------------------------------
        mov     dx,[ebx].hw_format
        and     dx,BPP_MASK
        cmp     dl,TWENTYFOUR_BPP
        jz      @F

        mov     ax,[ebx].bm_width
        mov     patt_width,ax
@@:
        ;--------------------------------------------------------------
        ; Some up front hw initializations not necessary for inclusion
        ; in the loop.  As we tile the color pattern across the destination
        ; rectangle, the source (X,Y) will remain the same.  However,
        ; we can fast path the case where the rop indicates a pattern
        ; copy.  If both the foreground and background mixes are
        ; FUNC_S, we will modify our pattern source to be the first row
        ; of "tiles" after the first row is complete.
        ;--------------------------------------------------------------
        WaitQIdle
        WaitQ   6
        mov     fFastBlt,0
        memregread      eax,Function_1
        and     ax,ROP2_FIELD           ; isolate mix mode
        cmp     ax,FUNC_S
        jnz     @F
        mov     fFastBlt,1
@@:
        or      ax,FUNC_2OP_COPY        ; variable data mode
        outwQ   FUNCTION_1,ax

        memregread      eax,Function_0
        and     ax,ROP2_FIELD           ; isolate mix mode
        cmp     ax,FUNC_S
        jz      @F
        mov     fFastBlt,0
@@:
        or      ax,FUNC_2OP_COPY        ; variable data mode
        outwQ   FUNCTION_0,ax

        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES)
        outwQ   X0,x_src                        ; set source x-y address
        outwQ   Y0,y_src

        ;--------------------------------------------------------------
        ; Initialize ECX with the number of scanlines in the destination
        ; rectangle.  Each iteration of the outer loop will output
        ; patt_height number of scanlines.
        ;--------------------------------------------------------------
        movzx   ecx,total_height
        inc     ecx

outer_tile_loop:
        push    ecx

        ;--------------------------------------------------------------
        ; If this is the last iteration and/or the destination is not
        ; as tall as the pattern height, we must only use as many
        ; scanlines of the pattern as necessary to complete the fill
        ; of the destination.
        ;--------------------------------------------------------------
        mov     dx,total_height                 ; compare total to patt height
        mov     ax,patt_height
        dec     ax
        usmin_ax dx                             ; get which ever is least
        outwQ   LY,ax                           ; set the height

        mov     di,patt_width                   ; get pattern width in di
        mov     bx,x_dst                        ; use bx as dest pointer

        ;--------------------------------------------------------------
        ; Initialize ECX with the number of pels across the destination
        ; rectangle.  Each iteration of the inner loop will output
        ; patt_width pels until one row of "tiles" is output.
        ;--------------------------------------------------------------
        movzx   ecx,total_width
        inc     ecx
inner_tile_loop:
        ;--------------------------------------------------------------
        ; The Destination Y coord. remains constant for each "tile"
        ; in this row.  The Destination X coord. gets incremented by
        ; the width of the pattern as we blit across.
        ;--------------------------------------------------------------
        WaitQ   5
        outwQ   Y1,y_dst                        ; set dest x-y address
        outwQ   X1,bx                           ; set destination x addr

        ;--------------------------------------------------------------
        ; If this is the last iteration and/or the destination is not
        ; as wide as the pattern width, we must only use as many
        ; pels of the pattern as necessary to complete the fill
        ; of the destination.
        ;--------------------------------------------------------------
        mov     ax,di                           ; get 1 based width in ax
        usmin_ax   cx                           ; pattern width or remainder
        dec     ax                              ; get zero based width
        outwQ   LX,ax                           ; set width of blt

        ;--------------------------------------------------------------
        ; Decrement our counter of the remaining work to do.  Note:
        ; our count is off by one here...the loop statement will take
        ; care of that.
        ;--------------------------------------------------------------
        sub     cx,ax

        ;--------------------------------------------------------------
        ; Blit one "tile" of the pattern.
        ;--------------------------------------------------------------
        outwQ   CMD_FLAGS,CMDPATTERN

        ;--------------------------------------------------------------
        ; Update the Destination X for the next tile in this row.
        ;--------------------------------------------------------------
        add     bx,di                           ; dest + one based offset
        loop    inner_tile_loop

        ;--------------------------------------------------------------
        ; After we have completed the first row of "tiles", we check
        ; the FastBlt flag to see if we can use this row as the new
        ; source for the remaining rows.  Since our new source is as
        ; wide as the destination rectangle, it eliminates multiple
        ; iterations across each row.  We can do this only when the
        ; mix is a pattern copy.  After reseting the source regs, clear
        ; the flag to prevent calling this code again.
        ;--------------------------------------------------------------
        cmp     fFastBlt,1
        jnz     short no_fast_blt
        WaitQ   2
        outwQ   X0,x_dst
        outwQ   Y0,y_dst
        mov     ax,total_width
        inc     ax
        mov     patt_width,ax
        mov     fFastBlt,0
no_fast_blt:

        ;--------------------------------------------------------------
        ; Update the Destination Y to output for the next row.
        ;--------------------------------------------------------------
        mov     ax,patt_height
        add     y_dst,ax

        pop     ecx
        mov     ax,patt_height
        sub     total_height,ax
        sub     cx,ax
        cmp     cx,0
        jg      outer_tile_loop

colorpat_done:

cEnd

ENDIF  ;HARD_DRAW
ENDIF  ;_8514

;***********************************************************************
;
; Function: PatDestBlt1to8
;
; Called by: PatDestBlt
;
; Purpose: carries out a bitblt operation for a pattern and destination
; rop.
; Assumes the calling function has not made the call until the hardware
; is free
;
;***********************************************************************
IFDEF _8514
IFDEF HARD_DRAW

;***********************************************************************
;
; PatDestBlt1To8
;
;       requires ebx to point to bitmap header
;
;***********************************************************************
        align   4
public  _PatDestBlt1To8
_PatDestBlt1To8 proc near

        IFDEF BPP24
        ; only one function to call for 24-bit color
        test    [_DDT], USE_24BPP
        jz      @F
        call    PattBlt24
        ret
@@:
        ENDIF

        ; if the pattern is one byte wide and 1 bit high call
        ; the special case 1x8 blt
        mov     eax, dword ptr [ebx].hw_width
        cmp     eax, 00000007h
        jnz     @F
        call    PattBlt1x8
        ret
IF 0
@@:
        ; call special case 8x8 blt to tile the pattern quickly
        cmp     eax, 00070007h
        jnz     @F
        call    PattBlt8x8
        ret
ENDIF
@@:
        ; we don't have a special case function here so just let
        ; the 8x8 blt do the best it can
        call    PattBlt8x8
        ret

_PatDestBlt1To8 endp

;***********************************************************************
;
; PattBlt1x8
;
;***********************************************************************
        align   4
cProc   PattBlt1x8, <PUBLIC,NODATA,NEAR>, <edi ,esi, ebx, edx, ebp>
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        IF 0
        localW  x_bias
        localW  y_bias
        localW  bmap_size
        ENDIF
        IFDEF S3
        localW  y_src
        localW  x_src
        ENDIF
cBegin

        ;--------------------------------------------------------------
        ; use ebx as a pointer to the destination bitmap header
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhDest

        ;--------------------------------------------------------------
        ; convert destination bitmap address to x and y for 8514 hardware
        ;--------------------------------------------------------------
        memregread      eax,dest_map
        mov     x_dst,ax
        ror     eax,16
        mov     y_dst,ax
        calc8514xy  [ebx].bitmap_address
        add     x_dst,dx
        add     y_dst,ax

        ;--------------------------------------------------------------
        ; set up the destination width and height
        ; pick up clipping from patdestblt routine
        ;--------------------------------------------------------------
        memregread      ax,dim1
        mov     total_width,ax
        memregread      ax,dim2
        mov     total_height,ax

        ;--------------------------------------------------------------
        ; determine which mono proc to use
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhSrc
        mov     ax, word ptr [ebx].hw_width     ; get zero based mono width
        mov     dx, word ptr [ebx].hw_height    ; get zero based mono height

        ;--------------------------------------------------------------
        ; special case for mono pattern 1byte by one scanline
        ; do a filled rect for one byte mono patterns
        ; load pattern into hw pattern regs
        ;--------------------------------------------------------------

        IFNDEF  S3

        WaitQ   8
        mov     eax,[ebx]                      ;Get base ptr to patt.
        LoadPattern <[eax]>                    ; get virtual bitmap

        ;--------------------------------------------------------------
        ; convert destination bitmap address to x and y for 8514 hardware
        ;--------------------------------------------------------------
        outwQ   X0,x_dst                       ; set destination x-y address
        outwQ   Y0,y_dst

        ;--------------------------------------------------------------
        ; set up the destination width and height
        ;--------------------------------------------------------------
        outwQ   LX,total_width
        outwQ   LY,total_height

        outwQ   MODE,(MODE_2DECODE+MD_PS_PATT) ; use pattern registers
        outwQ   CMD_FLAGS,CMDSOLID             ; blt the pattern

        ELSE    ;S3

        ;--------------------------------------------------------------
        ; blit the pattern across the width of the destination bitmap
        ;--------------------------------------------------------------
        WaitQIdle
        WaitQ   8
        mov     eax,[ebx]                       ; get pointer to virtual memory
        mov     al,[eax]                        ; get 8 bit pattern
        mov     ah,al                           ; get a 16 bit pattern
        memregread ecx,src_map                  ; Fetch the X-Bias
        and     ecx,7                           ; How much should we adjust the pattern?
        rol     ax,cl                           ; Align it.
        push    eax                             ; save it

        ;--------------------------------------------------------------
        ;          
        ;--------------------------------------------------------------
        memregread eax,Color_0                  ;Color_0 may need to be restored if
        outwQ   COLOR_0,ax                      ; this function is called mulitple times.

        outwQ   X0,x_dst                        ; set destination x addr
        outwQ   Y0,y_dst                        ; set dest y addr
        outwQ   LX,total_width
        outwQ   LY,total_height

        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE)
        outwQ   CMD_FLAGS,CMD_WCUR              ; blt as variable data
        pop     eax                             ; restore it
        mov     dx,COLOR_0_WAIT                 ; variable data port

        movzx   ecx,total_height
        inc     ecx
mono_pat_loop:
        push    ecx                             ; Save the outer loop counter.
        mov     cx,total_width
        inc     ecx
        add     ecx,0fh
        shr     ecx,4                           ; round off and get word count
        inc     ecx
mpl1:   out     dx,ax                           ; send it
        nop
        loop    mpl1
@@:     pop     ecx                             ; Restore outer loop counter
        loop    mono_pat_loop

        ENDIF   ; S3
cEnd

;***********************************************************************
;
; PattBlt8x8
;
;***********************************************************************

        align   4
cProc   PattBlt8x8, <PUBLIC,NODATA,NEAR>, <edi ,esi, ebx, edx, ebp>
        localW  y_dst
        localW  x_dst
        localW  y_bias
        localW  x_bias
        IFDEF S3
        localW  y_src
        localW  x_src
        ENDIF
        localW  total_height
        localW  total_width
        localW  bmap_size
cBegin

        ;--------------------------------------------------------------
        ; use ebx as a pointer to the destination bitmap header
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhDest

        ;--------------------------------------------------------------
        ; convert destination bitmap address to x and y for 8514 hardware
        ;--------------------------------------------------------------
        memregread      eax,dest_map
        mov     x_dst,ax
        ror     eax,16
        mov     y_dst,ax
        calc8514xy  [ebx].bitmap_address
        add     x_dst,dx
        add     y_dst,ax

        ;--------------------------------------------------------------
        ; set up the destination width and height
        ; pick up clipping from patdestblt routine
        ;--------------------------------------------------------------
        memregread      ax,dim1
        mov     total_width,ax
        memregread      ax,dim2
        mov     total_height,ax

        ; now work with source bitmap
        mov     ebx, AIxfer.pbmhSrc

        memregread ecx, patt_map
        ;--------------------------------------------------------------
        ; CMVC 80935
        ; 
        ; Nugget alignment is not necessary for S3.  See the discussion
        ; of S3 pattern tiling above.
        ;--------------------------------------------------------------
 ifndef S3
        mov     ax, x_dst               ; nugget align pattern biasing

        and     ax, 3
        add     cx, ax
        and     cx, 7
 endif
        mov     x_bias,cx               ; Keep x bias.

        shr     ecx, 16                 ; Get Y bias.


        mov     y_bias, cx

        mov     ax,[ebx].bm_width       ; bytesperline not always
        shr     ax,3                    ; set (72310)
        mov     [ebx].bytesperline,ax

        mov     dx, word ptr [ebx].hw_height ; get 0-based pattern height
        movzx   eax, dx
        inc     eax                     ; 1-based pattern height
        mul     BYTE PTR [ebx].bytesperline
        mov     bmap_size, ax           ; # bytes in pattern

        IFNDEF  S3

        ;--------------------------------------------------------------
        ; Some up front initializations not necessary for inclusion in the loop
        ;--------------------------------------------------------------
        WaitQ   3
        outwQ   MODE,(MODE_2DECODE+MD_PS_PATT)  ; use pattern registers
        outwQ   LX,total_width                  ; output the width
        outwQ   LY,0                            ; do one horizontal line
        movzx   ecx,total_height
        inc     ecx

        movzx   eax,y_bias                      ; mul y by bytes per line
        mul     BYTE PTR [ebx].bytesperline
        mov     di,ax

ps_lp:
        WaitQIdle
        WaitQ   5
        mov     esi,[ebx]                       ;Get base ptr to patt.
        add     si,di                           ;Add Y offset
        add     di,[ebx].bytesperline           ;Inc. Y bias
        cmp     di,bmap_size                    ;If patt height exceeded,
        jl      @F                              ; 
        mov     di,0                            ;start again at zero.
@@:
        ;--------------------------------------------------------------
        ; Need to rotate by xbias here! MRC
        ;--------------------------------------------------------------
        movzx   eax,[esi]
        push    cx                              ;need to use cl as a shifter
        mov     cx,x_bias
        rol     al,cl                           ;rotate by X bias
        pop     cx

        LoadPattern <eax>                       ;Call pattern macro.

        ;--------------------------------------------------------------
        ; blit the pattern across the width of the destination bitmap
        ;--------------------------------------------------------------
        outwQ   X0,x_dst                        ; set destination x addr
        outwQ   Y0,y_dst                        ; set dest y addr
        outwQ   CMD_FLAGS,CMDSOLID              ; blt the pattern
        inc     y_dst                           ; go to the next line

        dec     cx
        jnz     ps_lp                           ; copy pattern down destination

        ELSE    ;S3

        push    esi
        movzx   edi,dx                          ; keep 0-based pattern height

        ;--------------------------------------------------------------
        ; point to the pattern cache
        ;--------------------------------------------------------------
        calc8514xy  colorpatphysical
        mov     x_src,dx
        mov     y_src,ax

        ;--------------------------------------------------------------
        ; set up to load the mono pattern into the cache.  must set
        ; bottom scissors to access VRAM cache (74627)
        ;--------------------------------------------------------------
        WaitQIdle

        WaitQ   4
        outwQ   YMAX, YMAX_2DECODE+(SCR_S3_HEIGHT-1)
        outwQ   FUNCTION_0,(FUNC_2OP_COL0+FUNC_ZEROS); write 0s to bg
        outwQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_ONES); write 1s to fg
        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR+MD_UP_FALSE)

        WaitQ   5
        outwQ   LX,7                            ; output the width
        outwQ   LY,7                            ; do the pattern height
        outwQ   X0,x_src                        ; set destination x addr
        outwQ   Y0,y_src                        ; set dest y addr
        outwQ   CMD_FLAGS,CMD_WCUR              ; blt as variable data

        ;--------------------------------------------------------------
        ; load the cache.  since we may have a pattern <8 pels high,
        ; loop as needed to make an 8x8 pattern
        ;--------------------------------------------------------------
        mov     dx,COLOR_0_WAIT                 ; variable data port
        mov     ecx,8                           ; must load an 8x8

        ;--------------------------------------------------------------
        ; START OF CMVC 80935
        ; Make sure we account for the Y-Bias when setting the address
        ; into the pattern map for the first pattern byte.
        ;--------------------------------------------------------------
        mov     eax,[ebx]
        movzx   esi,y_bias
        add     eax,esi
        jmp     short ld_pat
        ;--------------------------------------------------------------
        ; END OF CMVC 80935
        ;--------------------------------------------------------------

ld_pat_loop:
        add     ax, [ebx].bytesperline
        inc     esi                             ; increment y bias
        cmp     esi,edi                         ; reset if past patt height
        jle     ld_pat
ld_pat_init:
        mov     esi,0                           ; start again at zero
        mov     eax,[ebx]
ld_pat:
        push    ecx
        push    eax
        mov     al,[eax]                        ; get 8 bit pattern
        mov     cx,x_bias
        rol     al,cl                           ; rotate by X bias
        out     dx,ax                           ; output line of pattern
        nop
        pop     eax
        pop     ecx
        loop    ld_pat_loop
        pop     esi

        ;--------------------------------------------------------------
        ; now blt the pattern into the target rectangle.  must change
        ; the mixes for this operation
        ;--------------------------------------------------------------
        WaitQIdle

        WaitQ   2
        memregread      eax,Function_1
        and     ax,ROP2_FIELD                   ; isolate mix mode
        or      ax,FUNC_2OP_COL1                ; screeen data mode
        outwQ   FUNCTION_1,ax
        memregread      eax,Function_0
        and     ax,ROP2_FIELD                   ; isolate mix mode
        or      ax,FUNC_2OP_COL0                ; screeen data mode
        outwQ   FUNCTION_0,ax

        WaitQ   8
        outwQ   LX,total_width                  ; output the width
        outwQ   LY,total_height                 ; do one horizontal line
        outwQ   X0,x_src                        ; set src x addr
        outwQ   Y0,y_src                        ; set src y addr
        outwQ   X1,x_dst                        ; set destination x addr
        outwQ   Y1,y_dst                        ; set dest y addr
        outwQ   MODE,(MODE_2DECODE+MD_PS_COPY)  ; use board data
        outwQ   CMD_FLAGS,CMDS3_PATTERN         ; blt the pattern

        ENDIF   ;~S3
cEnd

;***********************************************************************
;
; PattBlt24
;
; Made modifications for Excel patterns (74142) and PageMaker selection
; selection (74327) defects.
;
; Since we cache the entire bitmap, we should check that the
; pattern isn't too big for either the temporary stack space
; we're using (LCLPATT_SIZE bytes) or the actual VRAM cache.
; But we don't.  The cache will easily hold a 32x32 bitmap so
; there is lots of room for improvement in this routine. --edb
;
;***********************************************************************
IFDEF BPP24

; cache height should be a multiple of the pattern height.  in
; general, apps are not using patterns with heights exceeding 8 pels.
; we'll leave this at 24 so that it will become apparent when someone
; does start using bigger patterns
CACHE_HEIGHT    equ     24

; now we need a scratch area for biasing our pattern bitmap.  this
; should be big enough for the biggest pattern bitmap.  note that
; this is only big enough for an 8x32 pattern (32 bytes).  there
; is room enough in the cache for 32x32 (expanded 3 times) but that
; would use just too much stack here so we'll stick to 32 bytes
LCLPATT_SIZE    equ     20h

        align   4
cProc   PattBlt24, <PUBLIC,NODATA,NEAR>, <edi ,esi, ebx, edx, ebp>
        localW  x_dst
        localW  y_dst
        localW  total_width
        localW  total_height
        localW  x_bias
        localW  y_bias
        localW  bmap_size
        localW  y_src
        localW  x_src
        localW  fXOR
        localD  patt_width
        localD  patt_height
        localD  patt_origin
        localV  local_patt, LCLPATT_SIZE
cBegin

        ;--------------------------------------------------------------
        ; use ebx as a pointer to the destination bitmap header
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhDest

        ;--------------------------------------------------------------
        ; convert destination bitmap address to x and y for 8514 hardware
        ;--------------------------------------------------------------
        memregread      eax,dest_map
        mov     x_dst,ax
        ror     eax,16
        mov     y_dst,ax
        calc8514xy  [ebx].bitmap_address
        add     x_dst,dx
        add     y_dst,ax

        ;--------------------------------------------------------------
        ; set up the destination width and height
        ; pick up clipping from patdestblt routine
        ;--------------------------------------------------------------
        memregread      ax,dim1
        inc     ax                              ; 3x width for 24 bpp
        fast3x  ax, dx
        dec     ax
        mov     total_width,ax
        memregread      ax,dim2
        mov     total_height,ax

        ;--------------------------------------------------------------
        ; get info about mono pattern
        ;--------------------------------------------------------------
        mov     ebx, AIxfer.pbmhSrc

        movzx   eax, word ptr [ebx].hw_width
        movzx   edx, word ptr [ebx].hw_height
        mov     patt_height, edx
        mov     patt_width, eax

        ;--------------------------------------------------------------
        ; set up for pattern biasing
        ;--------------------------------------------------------------
        mov     eax,AIxfer.PatOrig      ; Basically how it was done
        movzx   ecx, x_dst              ; originally, except add to x_bias
        and     cx, 7                   ; instead of negating when negative,
        and     ax, 7                   ; to fix Pagemaker garbage (74327)
        sub     cx, ax
        jns     @F
        add     cx, 8
@@:     mov     x_bias, cx

        shr     eax, 10h
        movzx   ecx, y_dst
        and     ecx, patt_height
        and     eax, patt_height
        sub     ecx,eax
        jns     @F
        neg     ecx
@@:     mov     y_bias, cx

        mov     ax,[ebx].bm_width       ; bytesperline not always
        shr     ax, 3                   ; set (72310)
        mov     [ebx].bytesperline, ax

        movzx   eax, dx                 ; get 0-based pattern height
        inc     eax                     ; get 1-based
        mul     BYTE PTR [ebx].bytesperline
        mov     bmap_size, ax           ; # bytes in pattern

        mov     fXOR,0

        ;--------------------------------------------------------------
        ; Calculate and save the address where our pattern will be
        ; cached.  Remember, our X coord. will be tripled to account
        ; for 24-bits per pel.
        ;--------------------------------------------------------------
        mov     eax,colorpatphysical
        and     eax,0fffffffh
        mov     edi,eax                 ;(X,Y) is pel format.
        mov     y_src,ax                ;Y of cache.
        ror     eax,16
        fast3x  ax, dx
        mov     x_src,ax                ;X of cache in bytes.

        ;--------------------------------------------------------------
        ; In order to properly X-bias our pattern blt, we will create
        ; a local copy of the monochrome pattern that will be shifted
        ; to properly align the pattern origin and the destination.
        ;--------------------------------------------------------------
        push    esi                     ;Save 'em
        push    edi                     ;Save 'em

        mov     esi, dword ptr [ebx]    ; point to pattern
        lea     edi, local_patt         ; point to local copy

        movzx   edx, bmap_size
        movzx   eax, y_bias
        mul     BYTE PTR [ebx].bytesperline
        push    eax
        add     esi, eax

        mov     ecx, edx
        sub     cx,ax
        rep     movsb                   ;Move from offset to end.
        pop     ecx
        mov     esi,[ebx]
        rep     movsb                   ;Move from beginning to offset.

        movzx   ecx, x_bias
        lea     edi,local_patt
@@:
        mov     al,byte ptr [edi]
        rol     al,cl
        stosb
        dec     edx
        jnz     short @B

        pop     edi                     ;Restore 'em
        pop     esi                     ;Restore 'em

        ;--------------------------------------------------------------
        ; Our goal is to cache expand our monochrome pattern into
        ; a 24x24 byte area in off-screen VRAM.  This gives use an 8x24
        ; pel pattern which we can later tile repeatedly onto the screen.
        ; Currently, patt_height contains the zero-based height of the
        ; pattern.  (Valid one-based heights are 1, 2, 4, and 8.)  We
        ; divide our constant by the one-based height to determine how
        ; many times we have to call _Copy24MonoToVRAM() in order to
        ; fill our 8x24 pel cached pattern.
        ;--------------------------------------------------------------
        mov     eax, CACHE_HEIGHT
        mov     ecx, patt_height
        inc     ecx                             ; get 1-based height
        div     cx
        mov     ecx, eax                        ; count of patterns

        ;--------------------------------------------------------------
        ; Cache the pattern as many times as necessary to fill the
        ; 8x24 pel area.
        ;--------------------------------------------------------------
@@:
        xor     ax,ax
        push    ax                      ; start bits
        push    ONE_BPP                 ; Bitmap Format
        push    patt_height
        push    patt_width              ; width of bmap
        push    patt_width              ; width of blt
        push    edi
        lea     eax,local_patt          ; Get base ptr to local patt copy.
        push    eax
        call    _Copy24MonoToVRAM
        add     esp,26
        add     edi,patt_height
        inc     edi                     ;Remember, patt_height is zero-based!
        loop    @b

        ;--------------------------------------------------------------
        ; now do a color pattern blt screen to screen
        ; set up the destination width and height
        ; use the clip rect set up in patdestblt routine
        ;--------------------------------------------------------------
        mov     patt_height,CACHE_HEIGHT-1
;EDB    mov     patt_width,7
        mov     ax,x_dst
        fast3x  ax, dx
        mov     x_dst,ax

        ;--------------------------------------------------------------
        ; Some up front hw initializations not necessary for
        ; inclusion in the loop
        ;--------------------------------------------------------------
        WaitQIdle
        WaitQ   5
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES)
        memregread      eax,Function_1
        and     ax,ROP2_FIELD                   ; isolate mix mode
        cmp     ax,FUNC_S
        jz      @F
        ; set fxor to five as if it is xor if the real rop is not src_copy
        mov     fXOR,5
@@:
        or      ax,FUNC_2OP_COPY                ; variable data mode
        outwQ   FUNCTION_1,ax
        memregread      eax,Function_0
        and     ax,ROP2_FIELD                   ; isolate mix mode
        or      ax,FUNC_2OP_COPY                ; variable data mode
        outwQ   FUNCTION_0,ax
        outwQ   X0,x_src                        ; set source x-y address
        outwQ   Y0,y_src

pb24_width:
        movzx   ecx,total_width
        inc     ecx                             ; 1-based total width

        WaitQ   1
        mov     dx,total_height                 ; compare total to patt height
        mov     ax,word ptr patt_height
        usmin_ax dx                             ; get which ever is least
        outwQ   LY,ax                           ; set the height

        mov     ax,word ptr patt_width
        inc     ax
        fast3x  ax, dx
        mov     di,ax                           ; di is 1-based patt width
        mov     bx,x_dst                        ; use bx as dest pointer

        ;--------------------------------------------------------------
        ; blit the pattern across the width of the destination bitmap
        ;--------------------------------------------------------------
pb24_width_next:

        WaitQ   4
        outwQ   X1, bx                          ; set source x-y address
        outwQ   Y1,y_dst                        ; set dest x-y address
        mov     ax,di                           ; get 1 based width in ax
        usmin_ax   cx                           ; pattern width or remainder
        dec     ax                              ; get zero based width
        outwQ   LX,ax                           ; set width of blt
        sub     cx,ax                           ; alter remaining width to blt (less 1)
        outwQ   CMD_FLAGS,CMDPATTERN            ; blt the pattern
        add     bx,di                           ; dest + one based offset
        loop    pb24_width_next                 ; copy pattern across destination

        ;--------------------------------------------------------------
        ; update the height and check if we're all done
        ;--------------------------------------------------------------
        movzx   ecx, total_height
        inc     ecx
        mov     di, word ptr patt_height
        inc     di
        sub     cx, di                          ; adjust for direct blt
        jbe     pb24_exit

        ;--------------------------------------------------------------
        ; If there's mixing in the destination then we can't use the
        ; destination as the new source, so check if this is an XOR
        ; and if so, adjust the destination coordinates and use the
        ; same source pattern again
        ;--------------------------------------------------------------
        cmp     fXOR, 5
        jnz     short @F
        add     y_dst, di
        dec     cx
        mov     total_height, cx
        jmp     pb24_width
@@:
        ;--------------------------------------------------------------
        ; Set up for bltting downwards.  Use destination blt as the
        ; new source
        ;--------------------------------------------------------------
        WaitQIdle

        WaitQ   3
        outwQ   LX, total_width                 ; set to pattern width
        outwQ   X0, x_dst                       ; set new source
        mov     ax, y_dst                       ; get original destination
        outwQ   Y0, ax                          ; set as new source
        add     ax, di                          ; add 1-based pattern height
        mov     y_dst, ax
        mov     bx, ax                          ; use bx as dest pointer

pb24_height:
        ;--------------------------------------------------------------
        ; blit the pattern down the height of the screen
        ;--------------------------------------------------------------
        WaitQ   4
        outwQ   X1, x_dst
        outwQ   Y1, bx                          ; set dest y address
        mov     ax,di
        usmin_ax   cx                           ; pattern height or remainder
        dec     ax                              ; get zero based height
        outwQ   LY,ax                           ; set height of blt
        sub     cx,ax                           ; alter remaining height to blt (less 1)
        outwQ   CMD_FLAGS,CMDPATTERN            ; blt the pattern
        add     bx,di                           ; dest + 1-based offset
        shl     di,1                            ; double size of pattern @DMS
        loop    pb24_height                     ; any more lines to blt ?

pb24_exit:
cEnd
ENDIF ; BPP24

ENDIF ; HARD_DRAW
ENDIF ; _8514

;***********************************************************************
;
; Function: DestOnlyBlt
;
; Called by: eddb_bitblt in eddnbblt.c
;
; Purpose: carries out a bitblt operation for a destination only rop.
; Assumes the calling function has not made the call until the hardware
; is free
;
; NB destination invert is done as a source invert - see eddnbblt.c
; DST_ONLY_BLT for the full story
;***********************************************************************

        align   4
DestOnlyBlt  proc near

        push    esi
        push    edi
        push    ebx

;*********************************************************************;
; get the base address of the hardware registers
;*********************************************************************;
IFDEF _8514
        mov     esi,p8514Regs
ELSE
        pushxga
        movxga  pXGARegs
ENDIF

;*********************************************************************;
; use ebx as a pointer to the destination bitmap header
;*********************************************************************;
        mov             ebx, AIxfer.pbmhDest

;*********************************************************************;
; use edi to count the number of clip regions
;*********************************************************************;
        movzx           edi, word ptr AIxfer.cDestClipRects

;*********************************************************************;
; select the destination map
;*********************************************************************;
        memregwrite     pi_map_index_A, SEL_PIX_MAP_A

;*********************************************************************;
; write destination bitmap address to hardware mapA base
;*********************************************************************;
        mov             eax, [ebx].bitmap_address
        IFDEF  _8514
        IFDEF  HARD_DRAW
        and     eax,0fffffffh   ; clear the vram marker
        ENDIF
        ENDIF
        memregwrite     pi_map_base_ptr_A, eax

; write mapA width and height from bitmap header
        mov             eax, dword ptr [ebx].hw_width
        memregwrite     pi_map_size_A, eax

;*********************************************************************;
; write mapA format from bitmap header
;*********************************************************************;
        mov             ax, [ebx].hw_format
        memregwrite     pi_map_format_A, al

;*********************************************************************;
; use ebx to reference the clip rectangles
;*********************************************************************;
        mov     ebx, dword ptr AIxfer.pNextDestClipRect

;*********************************************************************;
; get the pixel op from the ds
;*********************************************************************;
        mov             edx, pixelop
        jmp             dest_decclip

dest_writepixop:
; write the pixel op to kick off the blt
        memregwrite     pixel_op, edx


IFDEF HARD_DRAW

        IFDEF   _8514

; convert destination bitmap address to x and y for 8514 hardware
; use ebx as a pointer to the destination bitmap header
        push    ebx
        push    eax

; convert destination bitmap address to x and y for 8514 hardware
; use ebx as a pointer to the destination bitmap header
        mov     ebx, AIxfer.pbmhDest

; convert destination bitmap address to x and y for 8514 hardware

        WaitQIdle

        WaitQ   8
        calc8514xy  [ebx].bitmap_address
        mov     bx,ax                           ; ax = bx = y_dst dx = x_dst
        memregread      ecx,dest_map
        mov     ax,dx
        add     ax,cx
IFDEF   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        mov     dx,3
        mul     dx
@@:
ENDIF
        outwQ   X1, ax
        outwQ   X0, ax                          ; ax is not destroyed by outwq
        ror     ecx,16
        mov     ax,bx
        add     ax,cx
        outwQ   Y1, ax
        outwQ   Y0, ax

; set up the destination width and height
; use the clip rect set up in patdestblt routine
        memregread      ax,dim1
IFDEF   BPP24
        test    [_DDT],USE_24BPP
        jz      @f
        inc     ax
        mov     dx,3
        mul     dx
        dec     ax
@@:
ENDIF
        outwQ   LX, ax
        memregread      ax,dim2
        outwQ   LY, ax
        outwQ   MODE, <MODE_2DECODE + MD_PS_ONES + MD_UP_FALSE>
        outwQ   CMD_FLAGS, CMDDESTONLY
        pop     eax
        pop     ebx

        ENDIF  ;_8514

ELSE   ; SOFT_DRAW
        saveregs
        call    _eddf_MESS
        restoreregs
ENDIF

dest_no_intersect:
; if there are no more clip regions then exit now
        or      edi, edi
        jnz     short destonly_nextclip
IFNDEF _8514
        popxga
ENDIF
        pop     ebx
        pop     edi
        pop     esi
        ret

destonly_nextclip:
;*********************************************************************;
; advance the global pointer to the clip rectangles
;*********************************************************************;
        add     ebx, len_clip_rect

dest_decclip:
; decrement the clip region counter
        dec     edi

dest_doclipping:
;*********************************************************************;
; clip the destination to the next clip region - using the hardware
; scissor is too slow as it 'draws' the area outside the clip but
; without updating the screen
;*********************************************************************;
; for a destination only blt the blt direction is always left to
; right, top to bottom so the target coordinates are correctly ordered
; in the parameter block
;*********************************************************************;

; find the maximum of the clip bottom edge and the destination
; bottom edge and copy this to ax and also save in ecx high word
        max             [ebx].clip_y0, AIxfer.Dest0Coord.y, ax
        mov             cx, ax
        shl             ecx, 10h

;*********************************************************************;
; find the minimum of the distances from the bottom edge (in ax) to the
; bottom edge of the bitmap and bottom edge of the target: put the
; value in eax high word
;*********************************************************************;
        mov             cx, ax
        sub             cx, AIxfer.Dest1Coord.y
        ja              dest_no_intersect
        sub             ax, [ebx].clip_y1
        ja              dest_no_intersect
        rmax            ax, cx
        neg             ax
        shl             eax, 10h

; find the maximum of the clip left edge and the destination left edge
; and store it in cx (y coordinate is in ecx high word)
; save on the stack until we're ready to use the hardware
        max             [ebx].clip_x0, AIxfer.Dest0Coord.x, cx

; find the minimum of the distances from the left edge (in ax) to the
; right edge of the bitmap and right edge of the target: put the value
; in the dimension registers (along with the height in eax high word)
; Before altering cx, save ecx (coordinates) on the stack so we can write
; it to the hardware later
        mov             ax, cx
        sub             ax, AIxfer.Dest1Coord.x
        ja              dest_no_intersect
        push            ecx
        sub             cx, [ebx].clip_x1
        jbe             short @F
        add             esp, 4
        jmp             dest_no_intersect
@@:     rmax            ax, cx
        neg             ax
IFNDEF _8514
        waitshort
ENDIF
        memregwrite     dimensions, eax

; Now set up the dest coords, and we also set the source coords just incase
; this is a dest invert operation being done as a source invert operation
; - see eddnbblt.c DST_ONLY_BLT
        pop             eax
        memregwrite     dest_map, eax
        memregwrite     src_map, eax

        jmp             dest_writepixop


DestOnlyBlt   endp

_TEXT         ends

END
