;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = CELLDRAW.ASM
;*
;* DESCRIPTIVE NAME = Draw from a LVB
;*
;*
;* VERSION      V2.0
;*
;* DATE         06/26/87
;*
;* DESCRIPTION  This module contains drawing functions which materialize the image 
;*              of a logical video buffer based on pseudocode placed in the stack
;*              by routine from the CELLSCAN.ASM module.                                      
;*
;* FUNCTIONS   InvertClippedRect 
;*             InvertScreenRect  
;*             InvertScreenRect  
;*                              
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   06/22/88                     Mitchell McLain [gssc!mmm] Modified
;*                                dev_ScrollRect for the 8514.
;*   09/01/90                     rajivg Ported dev_ScrollRect code into the
;*                                current 8514 driver.
;*****************************************************************************/

        .xlist

        include cmacros.inc
INCL_FONTFILEFORMAT   equ     1
INCL_DEV              equ     1
        include pmgre.inc
        include driver.inc
        include cellblt.inc
        include 8514.inc
        include 8514mem.inc
        include fontseg.inc
        include njmp.mac
        include assert.mac

        .list

        ??_out  celldraw

sBegin  PtrData
        externB screen_busy
sEnd

sBegin  VioSeg
        assumes cs,VioSeg

        externB ColorMap
        externW MyPtrVioSegData           ; For access to pointer data segment
        externW VioSegData              ; For access to Vio data segment

        public  InvertScreenRect
        public  AVioDrawText

;/***************************************************************************
;*
;* PUBLIC ROUTINE  InterpretAttributes 
;*
;* DESCRIPTION   = Pops a word of attribute information off the stack, adjusts the
;*                 drawing environment as necessary, and jumps to an appropriate 
;*                 drawing function. It presumes the EBP stack environment created 
;*                 by DrawImageRect.
;*                 
;*                This routine usually exits with a JMP rather than a RET! 
;*
;*                 SP = pReturnAddress?
;*                     ret
;*
;*                 Set up hardware clip rectangle
;*
;*                 Reverse Video
;*                     Reverse colors
;*
;*                 Set up hardware color registers
;*
;*                 LCID Changed?
;*                     Map the LCID to a Font Selector.
;*
;*                     Zero Selector?
;*                         Scan the pseudo code until the next control marker,
;*                             replacing offsets by SURROGATE_CHARACTER.
;*                         Change the Selector to reference the base symbol set.
;*
;*                     Load the selector into DS.
;*                     Set up the glyph mapping attributes
;*
;*                 Transparent or Opaque?
;*
;*                     Opaque:
;*
;*                            Underscoring or Reverse Video?
;*
;*                     Transparent:
;*
;*              -----------------------------------------------------------------------;
;*               InterpretAttributes begins with a prologue for establishing part
;*               of the environment assumed by the drawing functions.  The drawing
;*               functions are presumed to preserve or properly update this state
;*               information across cell clusters with a common set of attributes.
;*
;*               Set up the hardware clip rectangle first.  It remains constant
;*               throughout the display of the text.  Note that the clip rectangle is
;*               given as lower left/upper right instead of upper left/lower right as
;*               the 8514 would like it.
;*
;*               It appears that the text clip rectangle is different than the normal
;*               PM clip rectangle in terms of which edges are inclusive and which are
;*               exclusive, just as in the strblt path.  In PM, the left and bottom
;*               edges are inclusive and the top and right edges are exclusive.  The
;*               text path, however, is based on         code, and in         the top
;*               and left edges are inclusive and the bottom and right edges are
;*               exclusive.  Set up the hardware clip rectangle with that in mind.
;*              -----------------------------------------------------------------------;
;*
;*               Registers Destroyed:         
;*                     AH, AL, BH, BL, CX, DX 
;*               Registers Preserved:         
;*                     None                   
;*
;* INPUT         = Assumes a WORD of descriptor information is at [SS:SP].
;* OUTPUT        = SS:SP advances to the next pseudo code word.
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

define_CharRect_frame InterpretAttributes

cBegin  <nogen>

        GrabScreen  celldraw1,far,VioSeg ; Don't let cursor interfere
        assumes es,nothing              ; GrabScreen trashes ES


        WaitQ   8                       ; Wait for room on the queue

        mov     cx,wDestHeight          ; Height of destination bitmap
        mov     ax,cx

        sub     ax,rClipRect.rcs_pts2.pts_y  ; Top (flipped and inclusive)
        or      ax,YMIN_2DECODE
        .errnz   YMIN_2DECODE and 0000111111111111b
        outwQ   YMIN

        mov     ax,cx                   ; Height of destination bitmap
        sub     ax,rClipRect.rcs_pts1.pts_y  ; Bottom (flipped and exclusive)
        dec     ax
        or      ax,YMAX_2DECODE
        .errnz   YMAX_2DECODE and 0000111111111111b
        outwQ   YMAX

        mov     ax,rClipRect.rcs_pts1.pts_x  ; Left (inclusive)
        or      ax,XMIN_2DECODE
        .errnz   XMIN_2DECODE and 0000111111111111b
        outwQ   XMIN

        mov     ax,rClipRect.rcs_pts2.pts_x  ; Right (exclusive)
        dec     ax
        or      ax,XMAX_2DECODE
        .errnz   XMAX_2DECODE and 0000111111111111b
        outwQ   XMAX


;/*
;**       Other hardware setup:
;**
;**           Enable all planes for writing
;**           Set pattern source to be data from the host
;**           Set the dimensions of the character data columns
;*/

        outwQ   WRITE_ENABLE,0ffh       ; Enable all planes for writing

        outwQ   MODE,(MODE_2DECODE+MD_PS_VAR) ; Pattern source variable data

        mov     ax,wCellWidth           ; Read cell width
        dec     ax                      ; ...8514 wants it minus 1
        outwQ   LX                      ; 

        mov     ax,wCellHeight
        dec     ax                      ; Board wants 1 less than height
        or      ax,LY_2DECODE           ; Bits for secondary decode command
        outwQ   LY                      ; Inform board of height

;/*
;** Construct the horizontal clip flag.
;*/

        xor     ah,ah                   ; Assume there is no clipping
        mov     cx,wVertLineCount
        cmp     cx,wCellWidth
        je      @F
        not     ah                      ; All 1s mean there is clipping
@@:
        mov     bHorizontalClipMask,ah


;/*
;** Remember the current Y coordinate in a register, because the board has
;** to be informed of it for each character output.  But first, adjust
;** the coordinates to point to the upper left corner of the cell, instead
;** of possibly somewhere in the middle of the cell, which they will when
;** the cell is clipped somehow.  The reason for this is that we're going
;** to let the 8514 hardware do the clipping (presumably it's fast enough).
;*/

        mov     bx,xcoordStart
        sub     bx,wLeftLineOffset
        mov     di,ycoordStart
        sub     di,wTopLineOffset
        add     di,wCellHeight
        dec     di

;/*
;**  Construct an increment that is used to make updating text positions
;**  on the board faster and easier.
;** 
;**    1.  The distance to move X in order to get to the left edge of the
;**        column set.  This value is used to simulate the effect of a
;**        carriage return without a line feed.
;** 
;**  Note: The use of wDest3rdIncr takes on a little different meaning
;**        in this driver than the comments indicate in CELLBLT.INC,
;**        because the 8514 is addressed with XY coordinate values rather
;**        than directly into the video buffer, although the intent is
;**        the same.
;*/

        mov     cx,ax
        mov     ax,wCellWidth
        or      ch,ch                   ; Clip flag set?
        jnz     @F                      ; Yes, partial column, use wCellWidth
        mul     wFullCols               ; Some number of full columns
@@:
        mov     wDest3rdIncr,ax

;/*
;** The drawing functions use addresses in an upward sequence.  Hence
;** the need to have the direction flag cleared.
;*/

        cld

;/*
;** The following label is the return point for all the device-dependant
;** drawing functions.  Most of them terminate with a jmp instead of a ret.
;*/

next_attribute_cluster:

        cmp     sp,pReturnAddress       ; Have we exhausted the pseudocode?
        jne     ProcessAStream

        ReleaseScreen  celldraw1,far,VioSeg        ; Cursor can interfere again
        cld                             ; direction must be clear on return
        retn                            ; If so return to the scanner.


ProcessAStream:

        pop     si                      ; Get the new attribute set.

        push    bx                      ; save coordinate

        mov     ax,si
        and     ax,(AVioReverseVideoMask OR AVioTransparentMask)
        cmp     ax,AVioReverseVideoMask ; Check for Opaque with Reverse Video.
        jnz     set_hardware_colors

        xchg    ax,si                   ; For that case we do the reversing
        mov     bl,ah                   ;   by just swapping foreground and
        shr     ah,4                    ;   background color attributes.
        shl     bx,4
        or      ah,bl
        xchg    ax,si                   ; Put colors back in SI

set_hardware_colors:
        WaitQ   2                       ; Wait for room on the queue

        mov     cx,si                   ; Colors to CH
        mov     cl,ch
        shr     ch,4                    ; CH = background color and
        and     cx,0f0fh                ;   CL = foreground color
        xor     bx,bx
        mov     bl,ch                   ; BX = background color
        outbQ   COLOR_0,ColorMap[bx]    ; Set hardware background color
        mov     bl,cl                   ; BX = foreground index
        outbQ   COLOR_1,ColorMap[bx]    ; Set hardware foreground color

        test    si,AVioUnderscoreMask
        jz      set_up_registers

        mov     ax,wTopLineOffset
        add     ax,wScanLineCount
        cmp     ax,wCellHeight
        jz      set_up_registers
        and     si,(NOT AVioUnderscoreMask)


set_up_registers:
        xor     cx,cx                   ; Zero reference value
        mov     ax,AVioUnderscoreMask   ; If underscoring, bl => 0FFh else 0.
        and     ax,si
        cmp     cx,ax
        sbb     bx,bx
        mov     wUnderscoreMask,bx

        mov     ax,si                   ; Get the previous attribute set
        mov     cx,si
        xchg    ax,wLastAttributes      ; and preserve this attribute set
                                        ; for the next InterpretAttributes
                                        ; call.

        mov     bx,ax                   ; Compare the old
        xor     bx,si                   ; new LCID bit fields.
        and     bx,AVioLCIDMask         ; Are they different?
        jnz     set_up_lcid

        mov     ds,wselfontsave
        assumes ds,FontSeg

        jmp     short SameSymbolSet


set_up_lcid:
        and     si,AVioLCIDMask         ; If so set up DS for the new
        shl     si,1                    ; symbol set.
        mov     bx,wSymbolSetSelectors[si]
        or      bx,bx                   ; Is this selector usable?
        jnz     ValidSymbolSetSelector

;/*
;** If we don't have a usable selector, we use the selector for the
;** base symbol set, and map all of the glyph points for that LCID to
;** a surrogate glyph.
;*/

        mov     bx,ss                   ; Set up to scan forward
        mov     ds,bx                   ; through the glyphs on the
        cld                             ; stack.

        mov     bx,SURROGATE_CHARACTER
        mov     si,sp
        add     si,2                    ;We pushed BX above, must counter!

check_next_syllable:
        lodsw
        cmp     ax,-2
        ja      found_a_control_marker  ; -1 => control marker
        je      check_next_syllable     ; -2 => end of row action

        mov     [si-2],bx
        jmp     short check_next_syllable


found_a_control_marker:
        mov     bx,wSymbolSetSelectors[0]   ; Substitute the selector for
                                            ; the base symbol set.

ValidSymbolSetSelector:
        mov     wselfontsave,bx
        mov     ds,bx
        assumes ds,FontSeg

;/*
;** Here we set up the data which characterizes the font which is becoming
;** active.
;*/

        mov     bx,fsMetrics.foca_usLastChar
        inc     bx
        mov     wGlyphSpan,bx
        mov     bx,fsMetrics.foca_usFirstChar
        mov     wFirstGlyph,bx
        mov     bx,fsMetrics.foca_usDefaultChar
        mov     wDefaultGlyph,bx

        mov     si,cx

SameSymbolSet:
        WaitQ   2                       ; Wait for room on 8514 input queue

        mov     al,FUNC_S               ; Assume opaque cells.
        test    si,AVioTransparentMask  ; Opaque cells?
        jz      set_modes               ; Yes.
        mov     al,FUNC_D               ; No.

set_modes:
        or      al,FUNC_2OP_COL0        ; BG color source is COLOR 0
        .errnz  FUNC_2OP_COL0 and 011111b
        outwQ   FUNCTION_0              ; Background mode to 8514

        mov     al,FUNC_S               ; Foreground always opaque
        or      al,FUNC_2OP_COL1
        .errnz  FUNC_2OP_COL1 and 011111b
        outwQ   FUNCTION_1              ; Foreground mode to 8514
        pop     bx                      ; restore coordinate
        jmp     AVioDrawText

; NB: This routine does not include a RET instruction!


cEnd    <nogen>
page


;/***************************************************************************
;*
;* FUNCTION NAME = InvertClippedRect 
;*
;* DESCRIPTION   = This routine does the display work for the InvertTextCursor 
;*                 routine.  It is driven by enumerate_clip_rects.             
;*                                                                             
;* INPUT         = SS:SI is the stack frame address for InvertTextCursor.
;*                 SS:BX is the address of a rectangle structure which defines a
;*                        component of the region to be inverted.                             
;*                                                                             
;*                 Registers Destroyed:                                                       
;*                       AX, BX, CX, DX, DI, ES                                               
;*                 Registers Preserved:                                                       
;*                       BP, SI                                                               
;*                 Calls:
;*                       exclude, unexclude, InvertScreenRect
;*                                                                             
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

sEnd    VioSeg

sBegin  Code
        assumes cs,Code

cProc   InvertClippedRect,<PUBLIC,NEAR>
cBegin
        call    far ptr far_InvertClippedRect
cEnd

sEnd    Code


sBegin  VioSeg
        assumes cs,VioSeg

        assumes ds,nothing
        assumes es,nothing

define_Invert_Cursor_Frame far_InvertClippedRect


cBegin  <nogen>

;/*
;** First we save the stack frame for enumerate_clip_rects
;** and set the frame pointer to reference the local environment
;** of InvertTextCursor.
;*/

        push    bp
        mov     bp,si

        mov     fSomethingDrawn,1       ; to denote a non-null vis region

;/*
;** Now we retrieve the screen coordinates of the rectangle to invert.
;** For convenience we map the coordinates to top left origin.
;*/

        mov     di,wDestHeight
        mov     dx,di

        sub     di,ss:[bx].rcl_yBottom.lo
        sub     dx,ss:[bx].rcl_yTop.lo
        mov     cx,ss:[bx].rcl_xLeft.lo
        mov     si,ss:[bx].rcl_xRight.lo

;/*
;** If the rectangle is empty we do nothing.
;*/

        cmp     dx,di
        jge     null_invert_rect

        cmp     cx,si
        jge     null_invert_rect

;/*
;** Otherwise we save the coordinates on the stack
;** and exclude the mouse cursor.
;*/

        push    si
        push    cx
        push    dx
        push    di

        call    far_exclude
        GrabScreen  celldraw2,far,VioSeg           ; Don't let cursor interfere
        assumes es,nothing              ; GrabScreen trashes ES


;/*
;** Now we retrieve the coordinates and map them into
;** a set of parameters for driving the InvertRect routine.
;*/

        pop     di      ; ... Bottom ...
        pop     bx      ; ... Top    ...
        pop     cx      ; ... Left   ...
        pop     si      ; ... Right  ...

        call    InvertScreenRect

        ReleaseScreen  celldraw2,far,VioSeg        ; cursor can now interfere again
        call    far_unexclude

null_invert_rect:

;/*
;** Before we return to enumerate_clip_rects, we must restore SI and BP
;** to the values they had on entry.
;*/

        mov     si,bp
        pop     bp

;/*
;** enumerate_clip_rects requires a non-zero result to keep going.
;** A zero result stops the enumeration.
;*/

        mov     ax,sp
        ret_far

cEnd    <nogen>
page


;/***************************************************************************
;*
;* FUNCTION NAME = AVioDrawText  
;*
;* DESCRIPTION   = Interprets pseudo code on the stack to draw Vio character
;*                 cell images with possible horizontal clipping, but no    
;*                 underscoring.                                            
;*
;*                 NB: This routine exits with a JMP next_attribute_cluster8
;*                 rather than a RET.
;*
;* INPUT         =    BX -- Destination X coordinate
;*                    DI -- Destination Y coordinate                                           
;*                    DS -- The Segment selector for the Symbol Set we're using.               
;*                 SS:SP -- Pseudocode pointer.  This points to the next pseudo code           
;*                          syllable to process.
;*
;* OUTPUT        = SS:SP -- will move according to the pseudo code consumed by this           
;*                          function.                                                         
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


;/*
;**-----------------------------------------------------------------------;
;** There are different character output routines according to how many   
;** source bytes there are in the character defintion (1 or 2) and how    
;** many destination nybbles (1..5) need to be written to the 8514.       
;** Here we create a jump table for accessing these routines. The index   
;** into the jump table is: (num_source_bytes-1 + num_dest_nybbles).      
;** Note that the only possible combinations of source bytes and          
;** destination nybbles are (1,1), (1,2), (1,3), (2,3), (2,4) and (2,5)   
;**-----------------------------------------------------------------------;
;*/

jump_table:
        dw      never_used              ; Index 0
        dw      outchar_src1_nyb1       ; Index 1
        dw      outchar_src1_nyb2       ; Index 2
        dw      outchar_src1_nyb3       ; Index 3
        dw      outchar_src2_nyb3       ; Index 4
        dw      outchar_src2_nyb4       ; Index 5
        dw      outchar_src2_nyb5       ; Index 6


;/*
;** Macro for creating an entry into the table containing offsets of each
;** section of code that displays a particular row of a character.
;*/

ROW_START_OFFSET macro prow, routine
        dw      routine&_row_&prow
        endm


;/*
;** The table containing the offset of each section of code that displays a
;** particular row of a character.
;*/





DrawText    proc
        assumes ds,FontSeg
        assumes ss,cb_variables

never_used:     assert  sp,E,0          ; For debugging

adt_control_code:
        inc     si                      ; -1 => an attribute or return addr.
        njns    next_attribute_cluster
adt_next_row:
        sub     bx,wDest3rdIncr
        add     di,wCellHeight
        jmp     adt_process_pseudo_code

adt_substitute_or_control:
        add     si,wFirstGlyph          ; Add back in lowest defined glyph
        js      adt_control_code        ; Signed value indicated control code

        mov     si,wDefaultGlyph
        jmp     short adt_have_glyph_index

AVioDrawText    label   near

;/*-----------------------------------------------------------------------;
;**        The character generation code displays each character in
;**        rectangles wCellWidth wide by wCellHeight rows high.  This
;**        conforms to the way the character data is stored in host memory
;**        and turns out to be a fairly straightforward way to get the bits
;**        to the board.
;** 
;**        Here's what the board will need to know for each character of
;**        the text string to be displayed:
;** 
;**            (X0,Y0) - destination coordinates for the character
;**            LX,LY   - the dimensions of each rectangle of each character
;**                      cell (this is a constant value and has already
;**                      been sent to the board)
;**            The command indicating what the board should do:
;**                Horizontal Rectangle
;**                Using byte mode
;**                Using variable pattern data
;**                Increment X and Y as command proceeds
;**                Write up to eight pixels at-a-time
;**                Enable write access to the planes
;** 
;** -----------------------------------------------------------------------;
;** -----------------------------------------------------------------------;
;**  8514 Variable Data
;** 
;**  writing variable data is a rather complex task.  You do OUT COLOR_0,AX
;**  and the bits in AX are
;** 
;**                AX
;**               -----
;**               Bit 0    ignored
;**               Bit 1    Pel 7
;**               Bit 2    Pel 6
;**               Bit 3    Pel 5
;**               Bit 4    Pel 4
;**               Bits 5-8 ignored
;**               Bit 9    Pel 3
;**               Bit A    Pel 2
;**               Bit B    Pel 1
;**               Bit C    Pel 0
;**               Bits D-F ignored
;** 
;**  That's not too     you might say, but wait, there's more...
;**  The above is only true if you are nibble aligned.
;**  If your first pel is at X = 9 then taking 9 mod 4 = 1
;**  tells us the above rotates by 1: Bit B is Pel 0 etc.
;** -----------------------------------------------------------------------;
;*/


;/*
;** Start of character output loop                                      
;*/

        std                             ; will do characters upwards

adt_process_pseudo_code:

;/*
;** If SI is non-negative, it's a glyph index.  Negative values denote
;** control actions:  -1 => a signal to return control to InterpretAttributes.
;**                   -2 => the end of a row of cell images has been reached.
;**                         Move to the beginning of the next row.
;*/

        pop     si                      ; Fetch glyph index
        sub     si,wFirstGlyph          ; Subtract the lowest defined glyph
        cmp     si,wGlyphSpan           ; Check against number of defined glyphs
        jnb     adt_substitute_or_control ; Jump off if out of range

adt_have_glyph_index:
        add     si,si                   ; * 2
        mov     ax,si
        add     si,si                   ; * 4
        add     si,ax                   ; * 6
        .errnz  (size VIO_FONT_ENTRIES) - 6

;/*
;** Calculate remaining information needed on a per-character basis
;*/

        mov     si,fsCharOffset[si].fe_dBits.lo ; DS:SI -> character data


;/*
;**adt_character_column_loop:
;*/
        WaitQ   8                       ; Wait for 8514 input queue

        mov     ax,bx                   ; AX = destination X for this column
        outwQ   X0                      ; Set the hardware destination X
        mov     ax,di                   ; AX = destination Y for this column
        outwQ   Y0                      ; Set hardware destination Y
        outwQ   CMD_FLAGS,<CMD_C_HRECT+CMD_BYTE_HI+CMD_BYTE+CMD_FV_VAR+\
                CMD_DX+CMD_MA_ACCESS+CMD_PA_FOUR+CMD_RW_W>


        mov     cx,bx                   ; Put destination X into cx

        push    bx                      ; dest X : popped at label char_done
        push    di                      ; dest Y : popped at label char_done

        mov     ax,wCellWidth           ; Load ax with char width
        mov     bx,wCellHeight          ; Load bx with char height

        lea     si,[si+bx-1]            ; move si to end of definition

;/*
;** Make  DI = 2 * (source_bytes - 1 + dest_nibbles)  to index the main   
;** jmp tbl which jumps to the routine to draw the character of this size 
;*/

        and     cx,3                    ; Get initial shift required
        mov     di,cx                   ; Use di to index jump table
        add     di,ax                   ; Add on character width
        add     di,3                    ; Round up to next full nybble
        shr     di,2                    ; Div by 4 to get no. of nybbles

        dec     ax                      ; ax now has (char_width - 1)
        shr     ax,3                    ; Divide ax by eight

;/*
;** Now AX has (num_source_bytes - 1) and DI has (num_dst_nybbles)
;** Add these up to get the index into the jump table
;*/

        add     di,ax                   ; Get the index
        assert  di,BE,6
        shl     di,1                    ; Convert index to table offset

        mov     dx,COLOR_0              ; char output routines want this
        jmp     word ptr jump_table[di] ; Draw character

;/*
;** -----------------------------------------------------------------------;
;**  Explanation of what follows
;** 
;**  The jmp above dispatches to one of the "oxx" dispatch routines below.
;**  Each "oxx" possibility is represented below by
;**    o A jump table
;**    o a dispatch routine
;**    o a macro for generating the code which outputs the bits to the 8514
;**    o a "rept" sequence which invokes the macro many times (producing
;**      the equivalent of an unrolled loop).
;** 
;**  The "oxx" dispatch routine jumps into the unrolled loop so as to do
;**  the correct number of scanlines.  Each invokation of the macro
;**  processes two scanlines.  The final odd scan is handled at the end if
;**  it exists.
;** 
;**  Read o11 first. The others are not as well commented, but are similar.
;** -----------------------------------------------------------------------;
;**    !!! Your comment about the odd line on the end applies only to
;**    !!! some of the cases (I think the ones with odd numbers of nibbles
;**    !!! i.e. (1,1), (1,3), (2,3), (2,5)
;**    !!! In these cases the output from successive input bytes must
;**    !!! be paired up as the output is delivered 8 bits at a time.
;** 
;**  The loop works from the bottom row of the character up.  The first
;**  row is special because it is OR'd with the underscore mask to give
;**  any underscore highlighting needed.  The source data for this row
;**  (one or two bytes) is loaded before the macro generated code starts.
;** 
;**  On entry to any of the oxx routines:
;**    bx = CellHeight
;**    cx = low order two bits of Dest X (i.e. the "phase")
;**    dx = COLOR_0 port address
;**    si = end of definition !!! is this a pointer to the end of the input?
;**    the 8514A card has already been set up with command flags etc.
;** -----------------------------------------------------------------------;
;**
;** -----------------------------------------------------------------------;
;**  o11                                                                   
;**                                                                        
;**  Output routine for characters with one source byte and one            
;**  destination nybble. It will probably never be used because the        
;**  font width will have to be in the range 1..4, but we will provide it  
;**  for completeness.                                                     
;** -----------------------------------------------------------------------;
;*/

;/*
;** Generate the jump table                                               
;*/
        row     =   0                   ; define jump table
jmp_o11:
        dw      o11_one_row
        rept    MaxSymbolLines/2
        row     =   row + 1
        ROW_START_OFFSET    %row, o11   ; generates:  dw  o11_row_%row
        endm

;/*
;** Setup and dispatch (jump into unrolled loop)                          
;*/

        public  outchar_src1_nyb1      ; For debugging
outchar_src1_nyb1:

        add     cl,3                   ; phase plus positioning

        lodsb                          ; get left-hand pels, move up row
        or      ax,wUnderscoreMask     ; merge underscore mask

        mov     di,bx                  ; Use CellHeight as index to row output.
        and     di,0fffeH              ; Need even number number to index into
        jmp     word ptr jmp_o11[di]   ; the jmp tbl.  Odd scan done at end.


;/*
;** Define a macro to generate the code which puts bits out to the 8514   
;*/

Output11Row     macro   nrow            ; define row output macro
        public  o11_row_&nrow
o11_row_&nrow:

        mov     ah,al                   ; copy nibble to ah
        lodsb                           ; get next row
        ror     ax,cl                   ; phase and position for output
        out     dx,ax                   ; output rows
  IFE   nrow and 7
        WaitQ   8          ;!!! Needed? ; every eighth pair, wait for queue
        mov     dx,COLOR_0              ; recover port index
  ENDIF
  IF    nrow ne 1
        lodsb                           ; get next row, move up row
  ENDIF
                endm

;/*
;** Generate the code (the unrolled loop) via the above macro             
;*/

        row = MaxSymbolLines/2          ; Initialise the row count
        REPT    MaxSymbolLines/2        ; Repeat for half the max. no. of rows
        Output11Row %row
        row = row - 1
        ENDM

        test    bx,1                    ; test for odd height
        njz     char_done               ; if even, finished

        lodsb                           ; get next row, move up row

o11_one_row:
        mov     ah,al                   ; copy nibble to ah
        lodsb                           ; get next row
        ror     ax,cl                   ; phase and position for output
        out     dx,ax                   ; output row

        jmp     char_done               ; Finished !
page

;/*
;** o13                                                                   
;**                                                                       
;** Output routine for characters with one source byte and three          
;** destination nybbles. This will be used for half of the character      
;** output with 7 bit wide fonts.                                         
;*/

;/*
;** The trick is to get the source bits correctly placed to OUT into
;** the 8514 register.  There are 8 source bits per character for this
;** case.  I will number them 76543210 for the first char and hgfedcba
;** for the second character (7 and h are most sig bits, 0 and a are LSBs)
;** The comments will illustrate the case where the phase (cx) is 2
;** phase could be 1 or 2 (other phases don't ever fall into (1,3) case).
;**
;** In every OUT we send 16 bits of ax in the form
;** ...XXXX....XXXX.    where . is a bit the hardware ignores and X is a
;** MSB          LSB    bit that the hardware takes on board.
;** If we concatenate up the "X" bits and strip out the "." bits then
;** the bits we will actually send are ??76/5432/10??/??hg/fedc/ba??
;** where "/" just shows nibble boundaries and
;** "?" represent bits that the hardware will ignore because of the
;** nibble phase of the X target set up by the command.
;** (Remember the last part of variable data craziness -- can only send
;** whole nibbles with the data properly aligned.  The hardware masks
;** the data to put in part nibbles rather than shifting it).
;*/

        row     =   0                   ; define jump table
jmp_o13:
        dw      o13_one_row
        rept    MaxSymbolLines/2
        row     =   row + 1
        ROW_START_OFFSET    %row, o13
        endm


        public  outchar_src1_nyb3       ; For debugging
outchar_src1_nyb3:

        lodsb                           ; get left-hand pels, move up row
        or      ax,wUnderscoreMask      ; merge underscore mask
        mov     di,bx                   ; use height as index to row output
        and     di,0fffeH
        jmp     word ptr jmp_o13[di]

Output13Row     macro   nrow            ; define row output macro
        public  o13_row_&nrow
o13_row_&nrow:

        ror     ax,cl                   ; phase. ax = 10xxxxxx xx765432
        mov     ch,ah                   ; save remainder nibble cx = 10xxxxxx
        mov     ah,al                   ; position first two nibbles for output
                                        ; ax = xx765432 xx765432
        shr     ah,3                    ; ax = xxxxx765 xx765432
        shl     al,1                    ; ax = xxxxx765 x765432x
        out     dx,ax                   ; out goes ...xx76. ...5432.
                                        ; other bits not taken on board
        lodsb                           ; get next row, move up row
                                        ; ax = xxxxx765 hgfedcba
        ror     ax,cl                   ; phase. ax = baxxxxx7 65hgfedc
        xchg    ah,ch                   ; recall remainder, save final nibble
                                        ; ax = 10xxxxxx 65hgfedc ch = baxxxxx7
        ror     ax,3                    ; position. ax = edc10xxx xxx65hgf
        out     dx,ax                   ; output them
                                        ; out goes ...1076. ...65hg.
                                        ; other bits not taken on board
                                        ; Really ...10??. ...??hg. 10 finishes
                                        ; one char and hg starts next
        ror     ax,1                    ; back to byte register boundary
                                        ; ax = fedc10xx xxxx65hg
        mov     al,ch                   ; recall final nibble
                                        ; ax = fedc10xx baxxxxx7
        ror     ax,3                    ; position. ax = xx7fedc1 0xxbaxxx
        out     dx,ax                   ; out goes ...fedc....baxx.
  IFE   nrow and 1
        WaitQ   6                       ; every other pair, wait for queue
        mov     dx,COLOR_0              ; recover port index
  ENDIF
  IF    nrow ne 1
        lodsb                           ; get next row, move up row
  ENDIF
                endm

        row = MaxSymbolLines/2          ; Initialise the row count
        REPT    MaxSymbolLines/2        ; Repeat for half the max. no. of rows
        Output13Row %row
        row = row - 1
        ENDM

        test    bx,1                    ; test for odd height
        njz     char_done               ; if even, finished

        lodsb                           ; get next row, move up row

o13_one_row:
        ror     ax,cl                   ; phase
        rol     ax,4                    ; move MSNibble to ah
        rol     al,4                    ; swap nibbles in al
        rol     ax,1                    ; position nibbles for output
        out     dx,ax                   ; output them
        rol     ax,4                    ; position final nibble
        out     dx,ax                   ; and output it

        jmp     char_done       ; Finished
page

;/*
;** o23                                                                   
;**                                                                       
;** Output routine for characters with two source bytes and three         
;** destination nybbles. This will be used for all output of twelve       
;** pel wide fonts.                                                       
;*/

        row     =   0                   ; define jump table
jmp_o23:
        dw      o23_one_row
        rept    MaxSymbolLines/2
        row     =   row + 1
        ROW_START_OFFSET    %row, o23
        endm


        public  outchar_src2_nyb3       ; For debugging
outchar_src2_nyb3:

        mov     ah,[si+bx]              ; get right hand pels
        lodsb                           ; get left-hand pels, move up row
        or      ax,wUnderscoreMask      ; merge underscore mask

        mov     di,bx                   ; use height as index to row output
        and     di,0fffeH
        jmp     word ptr jmp_o23[di]

Output23Row     macro   nrow            ; define row output macro
        public  o23_row_&nrow
o23_row_&nrow:

        ror     ax,cl                   ; phase
        mov     ch,ah                   ; save remainder nibble in ch
        mov     ah,al                   ; copy left-hand nibbles
        shr     ah,3                    ; position first nibble for output
        shl     al,1                    ; position second nibble for output
        out     dx,ax                   ; output left-hand nibbles

        mov     ah,[si+bx]              ; get right-hand of next row
        lodsb                           ; get left-hand of next row
        ror     ax,cl                   ; phase
        xchg    ch,ah                   ; recall remainder nibble, save final
        ror     ax,3                    ; position next two output nibbles
        out     dx,ax                   ; output them
        ror     ax,1                    ; move nibbles to byte-register..
        mov     al,ch                   ; .. so can recall final nibble
        ror     ax,3                    ; position nibbles for output
        out     dx,ax                   ; output them
  IFE   nrow and 1
        WaitQ   6                       ; every other pair, wait for queue
        mov     dx,COLOR_0              ; recover port index
  ENDIF
  IF nrow ne 1
        mov     ah,[si+bx]              ; get right-hand of next row
        lodsb                           ; get left-hand of next row
  ENDIF
                endm

        row = MaxSymbolLines/2          ; Initialise the row count
        REPT    MaxSymbolLines/2        ; Repeat for half the max. no. of rows
        Output23Row %row
        row = row - 1
        ENDM

        test    bx,1                    ; test for odd height
        njz     char_done               ; if even, finished

        mov     ah,[si+bx]              ; get right-hand of next row
        lodsb                           ; get left-hand of next row

o23_one_row:
        ror     ax,cl                   ; phase
        rol     ax,4                    ; move MSNibble to ah
        rol     al,4                    ; swap nibbles in al
        rol     ax,1                    ; position nibbles for output
        out     dx,ax                   ; output them
        rol     ax,4                    ; position final nibble
        out     dx,ax                   ; and output it

        jmp     char_done               ; finished !
page

;/*
;** o24
;**                                                                       
;** Output routine for characters with two source bytes and four          
;** destination nybbles. This will be used for all output of sixteen      
;** pel wide fonts.                                                       
;*/

        row     =   0                   ; define jump table
jmp_o24:
        dw      0
        rept    MaxSymbolLines
        row     =   row + 1
        ROW_START_OFFSET    %row, o24
        endm


        public  outchar_src2_nyb4       ; For debugging
outchar_src2_nyb4:

        sub     cl,4                    ; phasing plus nibble shift
        neg     cl

        mov     ah,[si+bx]              ; get right hand pels
        lodsb                           ; get left-hand pels, move up row
        or      ax,wUnderscoreMask      ; merge underscore mask

        jmp     word ptr jmp_o24[bx]    ; use height as index to row output

Output24Row     macro   nrow            ; define row output macro
        public  o24_row_&nrow
o24_row_&nrow:

        rol     ax,cl                   ; phase and move MSNibble to ah
        rol     al,4                    ; swap 2nd and 3rd nibbles
        rol     ax,1                    ; position nibbles for output
        out     dx,ax                   ; output them
        rol     ax,4                    ; position 3rd and 4th nibbles
        out     dx,ax                   ; output them

  IFE   nrow and 3
        WaitQ   8                       ; every fourth row, wait for queue
        mov     dx,COLOR_0              ; recover port index
  ENDIF
  IF    nrow ne 1
        mov     ah,[si+bx]              ; get right hand pels
        lodsb                           ; get left-hand pels, move up row
  ENDIF
                endm

        row = MaxSymbolLines            ; Initialise the row count
        REPT    MaxSymbolLines          ; Repeat for each row
        Output24Row %row
        row = row - 1
        ENDM

        jmp     char_done       ; Finished
page


;/*
;** o25                                                                   
;**                                                                       
;** Output routine for characters with two source bytes and five          
;** destination nybbles.                                                  
;*/

        row     =   0                   ; define jump table
jmp_o25:
        dw      o25_one_row
        rept    MaxSymbolLines/2
        row     =   row + 1
        ROW_START_OFFSET    %row, o25
        endm


        public  outchar_src2_nyb5       ; For debugging
outchar_src2_nyb5:

        sub     cl,4                    ; phasing plus nibble shift
        neg     cl

        mov     ah,[si+bx]              ; get right hand pels
        lodsb                           ; get left-hand pels, move up row
        or      ax,wUnderscoreMask      ; merge underscore mask

        mov     di,bx                   ; use height as index to row output
        and     di,0fffeH
        jmp     word ptr jmp_o25[di]

Output25Row     macro   nrow            ; define row output macro
        public  o25_row_&nrow
o25_row_&nrow:

        rol     ax,cl                   ; phase and move MSNibble to ah
        mov     ch,ah                   ; save remainder nibble
        rol     al,4                    ; swap 2nd and 3rd nibbles
        rol     ax,1                    ; position nibbles for output
        out     dx,ax                   ; output them
        rol     ax,4                    ; position 3rd and 4th nibbles
        out     dx,ax                   ; output them

        mov     ah,[si+bx]              ; get right hand pels
        lodsb                           ; get left-hand pels, move up row

        rol     ax,cl                   ; phase and move MSNibble to ah
        xchg    al,ch                   ; recall remainder, save current 2,3
        rol     ax,9                    ; shift to output position
        out     dx,ax                   ; output them
        ror     ax,1                    ; back to byte register
        mov     ah,ch                   ; recall 2 and 3
        ror     ax,4                    ; position for output
        rol     al,4                    ; "
        rol     ax,1                    ; "
        out     dx,ax                   ; output 2, 3
        rol     ax,4                    ; shift round 4, 5
        out     dx,ax                   ; output 4, 5
        WaitQ   5                       ; every pair, wait for queue
        mov     dx,COLOR_0              ; recover port index
  IF nrow ne 1
        mov     ah,[si+bx]              ; get right-hand of next row
        lodsb                           ; get left-hand of next row
  ENDIF
                endm

        row = MaxSymbolLines/2          ; Initialise the row count
        REPT    MaxSymbolLines/2        ; Repeat for half the max. no. of rows
        Output25Row %row
        row = row - 1
        ENDM

        test    bx,1                    ; test for odd height
        njz     char_done               ; if even, finished

        mov     ah,[si+bx]              ; get right-hand of next row
        lodsb                           ; get left-hand of next row

o25_one_row:
        rol     ax,cl                   ; phase and move MSNibble to ah
        rol     al,4                    ; swap 2nd and 3rd nibbles
        rol     ax,1                    ; position nibbles for output
        out     dx,ax                   ; output them
        rol     ax,4                    ; position 3rd and 4th nibbles
        out     dx,ax                   ; output them
        ror     ax,4                    ; position 5th nibble
        out     dx,ax                   ; output it

        jmp     char_done       ; Finished

;/*
;** o12                                                                   
;**                                                                       
;** Output routine for characters with one source byte and two            
;** destination nybbles. This will be a very popular routine because it   
;** will be used for all output with 8 pel wide fonts and for half of     
;** the character output with 7 bit wide fonts.                           
;*/
        row     =   0                   ; define jump table
jmp_12:
        dw      0
        rept    MaxSymbolLines/2
        row     =   row + 1
        ROW_START_OFFSET    %row, o12
        endm


        public  outchar_src1_nyb2       ; For debugging
outchar_src1_nyb2:

        or      cl,4            ; shift through nibble plus phase

        test    bx,1            ; test for odd height
        jz      o12_even

        lodsb                   ; if odd, then get one row, underscore and out
        or      ax,wUnderscoreMask
        ror     ax,cl
        rol     al,4
        rol     ax,5
        out     dx,ax
        dec     si              ; set up next row pair
        lodsw
        dec     bx
        jmp     word ptr jmp_12[bx]

o12_even:
        dec     si                      ; it's even, set up next row pair
        lodsw                           ; set up ax with two-row defn
        or      ah,byte ptr wUnderscoreMask

        jmp     word ptr jmp_12[bx]


Output12Row macro prow                  ; define row output macro
        public o12_row_&prow
o12_row_&prow:
        ror     ax,cl           ; phase the rows
        rol     al,4            ; order and output rows
        rol     ax,1
        out     dx,ax
        rol     ax,4
        out     dx,ax
IFE row AND 3                  ; Every 4 double-rows
        WaitQ   8               ; Wait for empty 8514 queue
        mov     dx,COLOR_0      ; Set up DX with COLOR_0 port
ENDIF                           ; IFE row AND 3
IF row NE 1
        lodsw                   ; Read two rows of char definition
ENDIF
                endm

        row = MaxSymbolLines/2  ; Initialise the row count
        REPT    MaxSymbolLines/2 ; Repeat for half the max. no. of rows
        Output12Row     %row
        row = row - 1
        ENDM

                                ; Fall through to char_done


char_done:

        pop     di              ; recover coordinates
        pop     bx

;/*
;** If the text is clipped horizontally, then there is no control code
;** between the character codes on the stack, but they are expected to
;** be displayed in a column.  Therefore, after each character, the
;** destination coordinates must be moved back a text column and down
;** a row.
;*/

        add     bx,wCellWidth           ; Point to next cell across
        cmp     bHorizontalClipMask,0   ; Is this text clipped?
        njne    adt_next_row            ; Yes
        jmp     adt_process_pseudo_code

DrawText    endp
page

;/***************************************************************************
;*
;* FUNCTION NAME = InvertScreenRect 
;*
;* DESCRIPTION   = This routine inverts a rectangle of pixels on the screen.
;*                 It's used to toggle the text cursor.                     
;*                                                                          
;*                 Registers Destroyed:                                                       
;*                       AX, DX                                                               
;*                 Registers Preserved:                                                       
;*                       None                                                                 
;*                                                                          
;* INPUT         = BX  =  Top of rectangle    
;*                 CX  =  Left of rectangle                                                   
;*                 DI  =  Bottom of rectangle                                                 
;*                 SI  =  Right of rectangle                                                  
;*                                                                          
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

InvertScreenRect    proc    near

;/*
;** CAUTION: WaitQ and outwQ macros use AX and DX!  Don't put anything precious
;** in them.
;*/

        WaitQ   5                      ; Wait for an empty queue

;/*
;** Set up the hardware clip rectangle, so the rectangle can be inverted.
;** Plus, make all planes writable.
;*/

        mov     ax,bx
        or      ax,YMIN_2DECODE
        .errnz  YMIN_2DECODE and 0000111111111111b
        outwQ   YMIN

        mov     ax,cx
        or      ax,XMIN_2DECODE
        .errnz  XMIN_2DECODE and 0000111111111111b
        outwQ   XMIN

        mov     ax,di
        or      ax,YMAX_2DECODE
        .errnz  YMAX_2DECODE and 0000111111111111b
        outwQ   YMAX

        mov     ax,si
        or      ax,XMAX_2DECODE
        .errnz  XMAX_2DECODE and 0000111111111111b
        outwQ   XMAX

        outwQ   WRITE_ENABLE,WRITE_ALL_PLANES; Enable all planes for writing

        WaitQ   7                       ; Wait for an empty queue

        mov     ax,cx                   ; AX = starting X
        and     ax,XY_SIGNIFICANT       ; Mask off insignificant bits
        outwQ   X0                      ; Inform board of starting X
        mov     ax,bx                   ; AX = startying Y
        and     ax,XY_SIGNIFICANT       ; Mask off insignificant bits
        outwQ   Y0                      ; Inform board of starting Y
        mov     ax,si                   ; 0-based width of rectangle is right
        sub     ax,cx                   ;   X minus left X,
        dec     ax                      ;   minus 1.
        outwQ   LX                      ; Inform board of width
        mov     ax,di                   ; 0-based height of rectangle is bottom
        sub     ax,bx                   ;   Y minus top Y,
        dec     ax                      ;   minus 1.
        .errnz  LY_2DECODE
        outwQ   LY                      ; Inform board of height
        outbQ   FUNCTION_1,(FUNC_2OP_COL1+FUNC_ND) ; !dest inverts the rect
        outwQ   MODE,(MODE_2DECODE+MD_PS_ONES); Fill with solid pattern,
                                              ;   reference FUNCTION 1
        outwQ   CMD_FLAGS,<(CMD_C_HRECT+CMD_FV_FIX+CMD_DY+CMD_DX+CMD_MA_ACCESS+\
                CMD_PA_FOUR+CMD_RW_W)>
        ret

InvertScreenRect    endp

;/*
;**  The following routine is here only to satisfy a requirement in cellblt.asm
;*/
        public  SetDisplayDefaults
SetDisplayDefaults  proc    near
        ret
SetDisplayDefaults  endp

ifdef HW_BLT

;/***************************************************************************
;*
;* FUNCTION NAME = dev_ScrollRect
;*
;* DESCRIPTION   = Scroll a rectangle on the screen.  This is used by CharRect  
;*                 from drawimagerect in cellscan.asm.                          
;*                                                                          
;*                 Registers Preserved:                                                       
;*                       ES,SI,DI                                                             
;*                                                                          
;* INPUT         = NONE
;* OUTPUT        = DS = CodeData 
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/


cProc   dev_ScrollRect,<PUBLIC,FAR>,<si,di,es>
        parmW   x1
        parmW   y1
        parmW   horzcount
        parmW   vertcount
        parmW   rectwidth
        parmW   rectheight
        parmD   lpClipRect
        localW  xwidth
        localW  sx1
        localW  sx2
        localW  wHeightGapHW
cBegin
        mov     ds,VioSegData
        assumes ds,Data

;/*
;**do we have a negative starting position?
;**If we do, reset the x/y value to zero and
;**subtract the clipped amount from the
;**width/height.
;*/
        mov     ax,x1
        or      ax,ax
        jns     @f
        add     rectwidth,ax
        njs     dsr_exceptional_exit
        xor     ax,ax
        mov     x1,ax
@@:     mov     ax,y1
        or      ax,ax
        jns     @f
        add     rectheight,ax
        njs     dsr_exceptional_exit
        xor     ax,ax
        mov     y1,ax
@@:
        block_pointer

        WaitQ   8

        outwQ    WRITE_MASK_REG,0ffffh
        outwQ    READ_MASK_REG
        mov     dx,MISC_REG
        mov     ax,CMD_C_OUTLINE
        outwQ
        les     di,lpClipRect
        mov     bx,768
        mov     ax,bx
        sub     ax,es:rcs_pts1.pts_y[di]
        push    ax      ;save bottom
        dec     ax
        add     ax,YMAX_2DECODE
        outwQ
        mov     ax,bx
        sub     ax,es:rcs_pts2.pts_y[di]
        push    ax
        add     ax,YMIN_2DECODE
        outwQ
        mov     ax,es:rcs_pts2.pts_x[di]
        push    ax      ;save right
        dec     ax
        add     ax,XMAX_2DECODE
        outwQ
        mov     ax,es:rcs_pts1.pts_x[di]
        push    ax      ;save left
        add     ax,XMIN_2DECODE
        outwQ
        outwQ    FRGD_MIX_REG,<FUNC_2OP_COPY or FUNC_S>

;/*
;** Make sure that our top is below the clip and our
;** bottom about the bottom clip.
;*/

        xor     si,si
        mov     cx,x1         ;start
        mov     di,horzcount  ;delta x
        pop     ax            ;left clip edge
        cmp     cx,ax         ;Are we inside the clip?
        jge     @f
        sub     cx,ax         ;make the clip be our
        mov     si,cx         ;left side and subtract
        mov     cx,ax         ;clip-x from the width.
@@:
        mov     bx,cx
        mov     ax,di
        AbsVal  ax
        add     bx,ax         ;dest
        or      di,di         ;What direction are we
        jns     @f            ;going?
        xchg    cx,bx   ;start<->dest
@@:
        neg     ax
        add     si,rectwidth
        add     si,ax
        pop     ax          ;right clip
        mov     dx,cx
        add     dx,si
        cmp     dx,ax
        jle     @f
        mov     si,ax
        sub     si,cx
@@:

;/*
;**Save our x's and our widths
;*/

        mov     sx1,cx
        mov     sx2,bx
        mov     xwidth,si

;/*
;**Compute our Y's just like our X's
;*/
        xor     si,si
        mov     cx,y1         ;start
        mov     di,vertcount  ;delta y
        pop     ax      ;Top clip edge
        cmp     cx,ax
        jge     @f
        sub     cx,ax
        add     rectheight,cx
        mov     cx,ax

@@:
        mov     bx,cx
        mov     ax,di
        AbsVal  ax
        add     bx,ax         ;dest
        or      di,di
        jns     dsr_up
        xchg    cx,bx   ;start<->dest

        pop     ax
        mov     dx,ax
        sub     dx,bx
        add     dx,di
        jz      dsr_1
        or      dx,dx
        js      dsr_1

        mov     si,rectheight
        add     si,di
        mov     dx,cx
        add     dx,si
        cmp     ax,dx
        jle     @f
        mov     wHeightGapHW,0
        jmp     short dsr_specialcase_done

@@:
        mov     si,ax
        sub     si,cx

        sub     dx,ax

        mov     wHeightGapHW,dx
        jmp     short dsr_specialcase_done

dsr_1:
        mov     si,1
        mov     cx,bx
        mov     wHeightGapHW,0
        jmp     short dsr_specialcase_done


dsr_up:
        pop     dx
        neg     ax
        add     dx,ax
        cmp     dx,cx
        jle     @f

        mov     si,dx
        sub     si,cx
        jmp     short dsa_upcase_done

@@:     mov     si,1
        mov     bx,cx

dsa_upcase_done:
        mov     wHeightGapHW,0


dsr_specialcase_done:

        mov     di,xwidth      ;width
        dec     di
        dec     si

        WaitQ   8
        outwQ    MAJ_AXIS_PCNT,di
        outwQ    MISC_REG,si

        inc     si
        inc     di
        mov     dx,sx2     ;x2
        mov     ax,sx1     ;x1

;/*
;**Select the proper direction to
;**copy the rect.
;*/
        cmp     ax,dx  ;cmp x1,x2
        jl      @f
        cmp     cx,bx  ;cmp y1,y2
        jl      @f
        mov     di,dx
        mov     si,(CMD_C_CRECT+CMD_DY+CMD_DX+CMD_MA_ACCESS+CMD_RW_W)
        jmp     short do_it
@@:
        add     bx,si
        add     cx,si
        add     ax,di
        add     di,dx
        mov     si,(CMD_C_CRECT+CMD_MA_ACCESS+CMD_RW_W)
do_it:

        outwQ    X0,ax
        outwQ    X1,di
        outwQ    MISC_REG,si
        outwQ    Y0,cx
        outwQ    Y1,bx

;/*
;**Do it.
;*/
        outwQ    COMMAND_REG,si
dsr_exit:
        allow_pointer
        jmp      short dsr_really_exit

dsr_exceptional_exit:
        mov      wHeightGapHW,0

dsr_really_exit:
        mov      ax,wHeightGapHW
cEnd
endif;HW_BLT
        sEnd    VioSeg

        end
