;*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    60,132
        TITLE   XGASCROL.ASM -- Common Buffer Scroll Routines for EGA, VGA, BGA

;/*****************************************************************************
;*
;* SOURCE FILE NAME = XGASCROL.ASM
;*
;* DESCRIPTIVE NAME = BUFFERUPDATE scroll routines 
;*
;*
;* VERSION      V2.0
;*
;* DATE         
;*
;* DESCRIPTION  This module contains routines that run at ring 2 in    
;*              order to directly access the hardware.
;*
;* FUNCTIONS    ScrollUp, ScrollDown     
;*              ScrollLeft, ScrollRight
;* 
;* NOTES        NONE
;*             
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVIY =
;*   DATE      FLAG        APAR    CHANGE DESCRIPTION
;*   --------  ----------  -----   --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx   xxxxxxx
;*   03/25/89  @P1         D132    PL, DCR 132 changes
;*   04/11/91              D1348   NAKADA, Enable DBCS support in Vio-Window
;****************************************************************************/

        .286c                           ; 286 protect mode instructions

        .xlist
        INCLUDE struc.inc               ; Structure macro
        INCLUDE error2.inc              ; Subsystem error equates
        INCLUDE vdhstruc.inc            ; Buffer update data structures
        INCLUDE vdhctl.inc              ; Conditional Assemply Control  ;MS01
        INCLUDE vdhequ.inc              ; Buffer update equates
        INCLUDE xgamac.inc                                              ;@P1
        .list

        EXTRN   SetGenParms:NEAR        ; Set up general buffer update parms @P1

IF VDHCGA AND (1 - CGA_ALWAYS_FAST) ; IF VDHCGA AND NOT CGA_ALWAYS_FAST ;@P1

;/*
;** If CGA video memory accesses may need to wait for retrace,
;** these routines are necessary. (See MAKEFILE)
;*/

        extrn   CGA_REP_MOVSW:far                                       ;@P1
        extrn   CGA_REP_STOSW:far                                       ;@P1
        extrn   CGA_REP_MOVSB_INCSI_LOOP:far                            ;@P1
        extrn   CGA_REP_MOVSW_STOSW_LOOP:far                            ;@P1
        extrn   CGA_REP_INCDI_STOSB_LOOP:far                            ;@P1
        extrn   CGA_REP_STOSB_INCDI_LOOP:far                            ;@P1
        extrn   CGA_REP_LODSB_STOSW_LOOP:far                            ;@P1
        extrn   CGA_REP_MOVSB_INCDI_LOOP:far                            ;@P1
        extrn   CGA_REP_MOVSW_ADDSI2_LOOP:far                           ;@P1
ENDIF   ;VDHCGA                                                         ;@P1

IFDEF D1348 ;BufferUpdate with dbcs bits handling
        extrn   MoveUpLeftWrld:near
        extrn   MoveDownRightWrld:near
ENDIF ;D1348

R2CSEG  SEGMENT WORD    PUBLIC 'CODE'
        ASSUME  CS:R2CSEG,DS:NOTHING,ES:NOTHING

;/****************************************************************************
;*                                                                     
;* SUBROUTINE NAME:     ScrollLeft                                     
;*                                                                     
;* DESCRIPTIVE NAME:    Video device handler scroll left routine       
;*                                                                     
;* FUNCTION:    Process scroll left sub-function                       
;*              Scrolls a portion of the PVB, LVB left a specified     
;*              number of times and then fill the vacant portion       
;*              with the user specified cell.                          
;*                                                                     
;* ENTRY POINT: ScrollLeft                                             
;*   LINKAGE:   Near Call from BUFFERUPDATE rouinte                    
;*                                                                     
;* INPUT:                                                              
;*                                                                     
;* AX = 0                                                              
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)     
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)     
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)     
;*                                                                     
;* PARAMETER BLOCK FORMAT:                                             
;*                                                                     
;*   SIZE   DESCRIPTION                                                
;*   ----   -----------                                                
;*                                                                     
;*   WORD   Parameter length                                           
;*   WORD   Flags                     (target buffer - LVB, PVB)       
;*   DWORD  Application data address                                   
;*   DWORD  Application data2 address (cell to be used to fill void)   
;*   WORD   Index (5)                                                  
;*   WORD   Starting row              (top row)                        
;*   WORD   Starting column           (left column)                    
;*   WORD   Secondary row             (bottom row)                     
;*   WORD   Secondary column          (right column)                   
;*   WORD   RepeatFactor              (# of times to scroll)           
;*   WORD   LogicalBufSel                                              
;*                                                                     
;* OUTPUT:                                                             
;*                                                                     
;* EXIT-NORMAL: AX = 0                                                 
;*                                                                     
;* EXIT-ERROR:  AX = SetForScroll                                      
;*                                                                     
;* EFFECTS:     All                                                    
;*                                                                     
;* INTERNAL REFERENCES: SetForScroll,                                  
;*                                                                     
;* EXTERNAL REFERENCES: None                                           
;*                                                                     
;****************************************************************************/

                PUBLIC  ScrollLeft
ScrollLeft      PROC

        mov     bx,LEFT
        call    SetForScroll
        jc      sclfx

        test    [bp].ScrollFlags,DOMOVE
        jz      sclf10

        push    bx
        call    MoveUpLeft
        pop     bx

sclf10: call    FillRectWithCell
        xor     ax,ax

sclfx:  ret

ScrollLeft      ENDP


;/****************************************************************************
;*                                                                     
;* SUBROUTINE NAME:     ScrollUp                                       
;*                                                                     
;* DESCRIPTIVE NAME:    Video device handler scroll up routine         
;*                                                                     
;* FUNCTION:    Process scroll up sub-function                         
;*              Scrolls a portion of the PVB, LVB up a specified       
;*              number of times and then fill the vacant portion       
;*              with the user specified cell.                          
;*                                                                     
;* ENTRY POINT: ScrollUp                                               
;*   LINKAGE:   Near Call from BUFFERUPDATE rouinte                    
;*                                                                     
;* INPUT:                                                              
;*                                                                     
;* AX = 0                                                              
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)     
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)     
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)     
;*                                                                     
;* PARAMETER BLOCK FORMAT:                                             
;*                                                                     
;*   SIZE   DESCRIPTION                                                
;*   ----   -----------                                                
;*                                                                     
;*   WORD   Parameter length                                           
;*   WORD   Flags                     (target buffer - LVB, PVB)       
;*   DWORD  Application data address                                   
;*   DWORD  Application data2 address (cell to be used to fill void)   
;*   WORD   Index (3)                                                  
;*   WORD   Starting row              (top row)                        
;*   WORD   Starting column           (left column)                    
;*   WORD   Secondary row             (bottom row)                     
;*   WORD   Secondary column          (right column)                   
;*   WORD   RepeatFactor              (# of times to scroll)           
;*   WORD   LogicalBufSel                                              
;*                                                                     
;* OUTPUT:                                                             
;*                                                                     
;* EXIT-NORMAL: AX = 0                                                 
;*                                                                     
;* EXIT-ERROR:  AX = SetForScroll                                      
;*                                                                     
;* EFFECTS:     All                                                    
;*                                                                     
;* INTERNAL REFERENCES: SetForScroll,                                  
;*                                                                     
;* EXTERNAL REFERENCES: None                                           
;*                                                                     
;****************************************************************************/

                PUBLIC  ScrollUp
ScrollUp        PROC
        mov     bx,UP
        call    SetForScroll
        jc      scupx

        test    [bp].ScrollFlags,DOMOVE
        jz      scup10

        push    bx
        call    MoveUpLeft
        pop     bx

scup10: call    FillRectWithCell
        xor     ax,ax

scupx:  ret

ScrollUp        ENDP


;/****************************************************************************
;*                                                                     
;* SUBROUTINE NAME:     ScrollRight                                    
;*                                                                     
;* DESCRIPTIVE NAME:    Video device handler scroll right routine      
;*                                                                     
;* FUNCTION:    Process scroll right sub-function                      
;*              Scrolls a portion of the PVB, LVB right to a specified 
;*              number of times and then fill the vacant portion with  
;*              the user specified cell.                               
;*                                                                     
;* ENTRY POINT: ScrollRight                                            
;*   LINKAGE:   Near Call from BUFFERUPDATE rouinte                    
;*                                                                     
;* INPUT:                                                              
;*                                                                     
;* AX = 0                                                              
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)     
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)     
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)     
;*                                                                     
;* PARAMETER BLOCK FORMAT:                                             
;*                                                                     
;*   SIZE   DESCRIPTION                                                
;*   ----   -----------                                                
;*                                                                     
;*   WORD   Parameter length                                           
;*   WORD   Flags                     (target buffer - LVB, PVB)       
;*   DWORD  Application data address                                   
;*   DWORD  Application data2 address (cell to be used to fill void)   
;*   WORD   Index (6)                                                  
;*   WORD   Starting row              (top row)                        
;*   WORD   Starting column           (left column)                    
;*   WORD   Secondary row             (bottom row)                     
;*   WORD   Secondary column          (right column)                   
;*   WORD   RepeatFactor              (# of times to scroll)           
;*   WORD   LogicalBufSel                                              
;*                                                                     
;* OUTPUT:                                                             
;*                                                                     
;* EXIT-NORMAL: AX = 0                                                 
;*                                                                     
;* EXIT-ERROR:  AX = SetForScroll                                      
;*                                                                     
;* EFFECTS:     All                                                    
;*                                                                     
;* INTERNAL REFERENCES: SetForScroll,                                  
;*                                                                     
;* EXTERNAL REFERENCES: None                                           
;*                                                                     
;****************************************************************************/

                PUBLIC  ScrollRight
ScrollRight     PROC

        mov     bx,RIGHT
        call    SetForScroll
        jc      scrtx

        test    [bp].ScrollFlags,DOMOVE
        jz      scrt10

        push    bx
        call    MoveDownRight
        pop     bx

scrt10: call    FillRectWithCell
        xor     ax,ax

scrtx:  ret

ScrollRight     ENDP


;/****************************************************************************
;*                                                                     
;* SUBROUTINE NAME:     ScrollDown                                     
;*                                                                     
;* DESCRIPTIVE NAME:    Video device handler scroll down routine       
;*                                                                     
;* FUNCTION:    Process scroll down sub-function                       
;*              Scrolls a portion of the PVB, LVB down a specified     
;*              number of times and then fill the vacant portion       
;*              with the user specified cell.                          
;*                                                                     
;* ENTRY POINT: ScrollDown                                             
;*   LINKAGE:   Near Call from BUFFERUPDATE rouinte                    
;*                                                                     
;* INPUT:                                                              
;*                                                                     
;* AX = 0                                                              
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)     
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)     
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)     
;*                                                                     
;* PARAMETER BLOCK FORMAT:                                             
;*                                                                     
;*   SIZE   DESCRIPTION                                                
;*   ----   -----------                                                
;*                                                                     
;*   WORD   Parameter length                                           
;*   WORD   Flags                     (target buffer - LVB, PVB)       
;*   DWORD  Application data address                                   
;*   DWORD  Application data2 address (cell to be used to fill void)   
;*   WORD   Index (4)                                                  
;*   WORD   Starting row              (top row)                        
;*   WORD   Starting column           (left column)                    
;*   WORD   Secondary row             (bottom row)                     
;*   WORD   Secondary column          (right column)                   
;*   WORD   RepeatFactor              (# of times to scroll)           
;*   WORD   LogicalBufSel                                              
;*                                                                     
;* OUTPUT:                                                             
;*                                                                     
;* EXIT-NORMAL: AX = 0                                                 
;*                                                                     
;* EXIT-ERROR:  AX = SetForScroll                                      
;*                                                                     
;* EFFECTS:     All                                                    
;*                                                                     
;* INTERNAL REFERENCES: SetForScroll,                                  
;*                                                                     
;* EXTERNAL REFERENCES: None                                           
;*                                                                     
;****************************************************************************/

                PUBLIC  ScrollDown
ScrollDown      PROC

        mov     bx,DOWN
        call    SetForScroll
        jc      scdnx

        test    [bp].ScrollFlags,DOMOVE
        jz      scdn10

        push    bx
        call    MoveDownRight
        pop     bx

scdn10: call    FillRectWithCell
        xor     ax,ax

scdnx:  ret

ScrollDown      ENDP

;/****************************************************************************
;*                                                                     
;* SUBROUTINE NAME:     LVBToPVB                                       
;*                                                                     
;* DESCRIPTIVE NAME:    Video device handler copy LVB rectangle to PVB 
;*                                                                     
;* FUNCTION:    Copy a rectangle from an LVB on to the PVB             
;*                                                                     
;* ENTRY POINT: LVBToPVB                                               
;*   LINKAGE:   Near Call from BUFFERUPDATE rouinte                    
;*                                                                     
;* INPUT:                                                              
;*                                                                     
;* AX = 0                                                              
;* SS:BP  --->  Stack frame                     (see VDHSTRUC.INC)     
;* DS:SI  --->  Parameter block buffer          (see XGABUFUP.ASM)     
;* ES:DI  --->  Mode data in environment buffer (see XGABUFUP.ASM)     
;*                                                                     
;* PARAMETER BLOCK FORMAT:                                             
;*                                                                     
;*   SIZE   DESCRIPTION                                                
;*   ----   -----------                                                
;*                                                                     
;*   WORD   Parameter length                                           
;*   WORD   Flags                     (target buffer - LVB, PVB)       
;*   DWORD  Application data address                                   
;*   DWORD  Application data2 address (cell to be used to fill void)   
;*   WORD   Index (4)                                                  
;*   WORD   Starting row              (top row)                        
;*   WORD   Starting column           (left column)                    
;*   WORD   Secondary row             (bottom row)                     
;*   WORD   Secondary column          (right column)                   
;*   WORD   RepeatFactor              (# of times to scroll)           
;*   WORD   LogicalBufSel                                              
;*                                                                     
;* OUTPUT:                                                             
;*                                                                     
;* EXIT-NORMAL: AX = 0                                                 
;*                                                                     
;* EXIT-ERROR:  AX = SetForScroll                                      
;*                                                                     
;* EFFECTS:     All                                                    
;*                                                                     
;* INTERNAL REFERENCES: SetForScroll,MoveLVBRectToPVB                  
;*                                                                     
;* EXTERNAL REFERENCES: None                                           
;*                                                                     
;****************************************************************************/

                PUBLIC  LVBToPVB                                ;@P1 begin
LVBToPVB        PROC

        xor     ax,ax                   ; clear error code
        push    ds:[si].RepeatFactor    ; save the old repeat factor
        push    ds:[si].Flags           ; save the old flags
        test    [si].Flags, PVB_SEL_BIT ; write to the PVB
        jz      ltpx                    ;   NO, do nothing

        or      [si].Flags, LVB_SEL_BIT ; LVB bit needs to be set

        mov     ds:[si].RepeatFactor,-1 ; this will be a scroll without move
        mov     bx,LVBPVB               ; pretend to be a scroll function
        call    SetForScroll            ; get the scroll parameters
        jc      ltpx

        call    MoveLVBRectToPVB        ; The fill rect is the rect to move
        xor     ax,ax

ltpx:   lds     si,[bp].ParmBuf
        pop     ds:[si].Flags           ; restore the old flags
        pop     ds:[si].RepeatFactor    ; 
        ret

LVBToPVB        ENDP                                            ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = SetForScroll
;*
;* DESCRIPTION   = 
;*
;*      Set up parameters for a scroll
;*      SetForScroll does range checking and parameter adjustment for
;*      all scroll functions.  This is valid for 2 and 4 byte cell LVBs
;*      and for the fill cell supplied as 2 or 4 bytes.
;*
;*      All scrolls consist of two basic operations.  The first is
;*      move a rectangle.  The second is fill a rectangle.  The rectangle
;*      to be moved will be NULL if the scroll is greater than the
;*      depth of the rectangle in the direction of movement.
;*
;*      This routine calculates the source rectangle and destination
;*      rectangle for the move.  For UP and LEFT scrolling, the rectangle
;*      should be copied beginning to end.  For DOWN and RIGHT the copy
;*      should go from end to beginning.  This routine provides the
;*      correct buffer offset for the appropriate starting point of
;*      the rectangle.
;*
;* INPUT         = 
;*
;*          BX - Flag indicating the type of scroll (UP,DOWN,LEFT,RIGHT)
;*          SS:BP - local data storage area
;*          DS:SI - user passed parameter block
;*          ES:DI - mode data structure
;*          [bp].minrow - index of top most row in LVB (PVB coordinates)
;*          [bp].mincol - index of left most row in LVB (PVB coordinates)
;*          [bp].maxrow - index of bottom most row in LVB (PVB coordinates)
;*          [bp].maxcol - index of right most row in LVB (PVB coordinates)
;*              
;* OUTPUT        = 
;*
;*       CARRY CLEAR
;*           BX = LVB selector if LVB scroll is indicated else 0
;*
;*           [bp].PVB_Sel = PVB selector if PVB scroll is indicated else 0
;*
;*           [bp].ScrollFlags  = either DOFILL or DOMOVE+DOFILL
;*
;*           [bp].RowsToFill   = rows to be filled with the default cell
;*
;*           [bp].PVBFillOff   = offset of start of PVB fill rectangle
;*           [bp].PVBFillCount = # of bytes per fill line in PVB
;*           [bp].PVBFillSkip  = # of bytes to skip to reach next PVB line
;*
;*           [bp].LVBFillOff   = offset of start of LVB fill rectangle
;*           [bp].LVBFillCount = # of bytes per fill line in LVB
;*           [bp].LVBFillSkip  = # of bytes to skip to reach next LVB line
;*
;*           [bp].FillCellLow  = first word of default fill cell
;*           [bp].FillCellHigh = second word of default fill cell
;*
;*         if DOMOVE is set in ScrollFlags
;*
;*           [bp].RowsToMove     = number of rows to move
;*
;*           [bp].PVBMoveCount   = # of bytes per PVB row to move
;*           [bp].PVBMoveSkip    = # of bytes to skip to get to the next row
;*           [bp].PVBMoveSrcOff  = offset to start of PVB source buffer
;*           [bp].PVBMoveDestOff = offset to start of PVB destination buffer
;*
;*           [bp].LVBMoveCount   = # of bytes per PVB row to move
;*           [bp].LVBMoveSkip    = # of bytes to skip to get to the next row
;*           [bp].LVBMoveSrcOff  = offset to start of PVB source buffer
;*           [bp].LVBMoveDestOff = offset to start of PVB destination buffer
;*
;*       CARRY SET
;*           [bp].ScrollFlags = 0
;*
;*   CALLS   SetBaseRects, AdjustRects, CalcMoveValues, CalcFillValues
;*
;*   USES    AX,CX,DX,SI,DS,FLAGS
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

                PUBLIC  SetForScroll                            ;@P1 begin
SetForScroll    PROC

        call    SetGenParms             ; set general parameters for all
                                        ; buffer update functions
        call    SetBaseRects            ; do basic value setting on source,
                                        ; destination and fill rectangles

        .if     <nc>                    ; parms from SetBaseRects are good

            call    AdjustRects         ; adjust the rectangle values for the
                                        ; specific type of scroll

                                        ; At this point we have source and
                                        ; and destination rectangles that are
                                        ; both entirely contained in the LVB.
                                        ; We have also calculated the
                                        ; rectangle that will be left void
                                        ; when the moved rectangle is copied.

            test    [bp].ScrollFlags,DOMOVE ; Are move rectangles != NULL?
            .if     <nz>                ;   Yes, calculate the move parms
                call    CalcMoveValues  ;   and buffer lengths
            .endif
            call    CalcFillValues      ; calculate the fill rectangle parms
            mov     bx, [bp].LVB_SEL    ; (bx) = LVB selector

            clc

        .endif

        ret

SetForScroll    ENDP                                            ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = SetBaseRects
;*
;* DESCRIPTION   = 
;*
;*      Set default values for source, dest and fill rectangles
;*
;*      SetBaseRects does basic rectangle value setting for the source
;*      and destination rectangles for the rectangle that needs to be
;*      moved as part of the scroll.  Default values for the fill
;*      rectangle are also set.
;*
;*      This routine also checks and adjusts the RepeatFactor, the number
;*      of rows or columns to be scrolled.  If it is 0, an error is returned.
;*
;* INPUT     =  BX - Flag indicating the type of scroll (UP,DOWN,LEFT,RIGHT)
;*              SS:BP - local data storage area
;*              DS:SI - user passed parameter block
;*              ES:DI - mode data structure
;*              [bp].minrow - index of top most row in LVB (PVB coordinates)
;*              [bp].mincol - index of left most row in LVB (PVB coordinates)
;*              [bp].maxrow - index of bottom most row in LVB (PVB coordinates)
;*              [bp].maxcol - index of right most row in LVB (PVB coordinates)
;*
;* OUTPUT   =
;*
;*          CARRY CLEAR
;*              CX = repeat factor
;*              [bp].ScrollFlags  = DOMOVE+DOFILL
;*              [bp].topscroll    = ParmBlock->Row
;*              [bp].topdest      =   "
;*              [bp].topfill      =   "
;*              [bp].leftscroll   = ParmBlock->Col
;*              [bp].leftdest     =   "
;*              [bp].leftfill     =   "
;*              [bp].rightscroll  = ParmBlock->Row2
;*              [bp].rightdest    =   "
;*              [bp].rightfill    =   "
;*              [bp].bottomscroll = ParmBlock->Col2
;*              [bp].bottomdest   =   "
;*              [bp].bottomfill   =   "
;*
;*          CARRY SET
;*              [bp].ScrollFlags = 0
;*
;*
;* CALLS   none
;*
;* USES    AX,CX,FLAGS
;*
;* NOTES
;*
;* PSEUDOCODE
;*
;*                 topscroll = parmrow
;*                 leftscroll = parmcol
;*                 bottomscroll = parmrow2
;*                 rightscroll = parmcol2
;*                 topdest = topscroll
;*                 leftdest = leftscroll
;*                 bottomdest = bottomscroll
;*                 rightdest = rightscroll
;*                 topfill = topscroll
;*                 leftfill = leftscroll
;*                 bottomfill = bottomscroll
;*                 rightfill = rightscroll
;*                 DoMoveFlag = TRUE
;*                 DoFillFlag = TRUE
;*                 if  (RepCount == 0)   
;*                     DoMoveFlag = FALSE
;*                     DoFillFlag = FALSE
;*                     set error
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                PUBLIC  SetBaseRects                            ;@P1 begin
SetBaseRects    PROC
        mov     ax,[si].Row         ; set all of the top coordinates
        .if     <ax b [bp].minrow> near
            mov     ax,[bp].minrow
        .endif
                                        ; BUGBUG this is really should not be
        .if     <ax a [bp].maxrow> near ; here, but it is necessary to pass
            mov     ax,[bp].maxrow      ; the component tests.  Remove it at
        .endif                          ; the first opertunity.

        test    bx,LVBPVB
        .if     <z>                     ; NOT LVB to PVB
            .if     <ax b es:[di].ScrlRectTop> near
                mov     ax,es:[di].ScrlRectTop
            .endif

            .if     <ax a es:[di].ScrlRectBottom> near
                mov     ax,es:[di].ScrlRectBottom
            .endif
        .endif

        mov     [bp].topscroll,ax
        mov     [bp].topdest,ax
        mov     [bp].topfill,ax

        mov     cx,[si].Row2        ; set all of the bottom coordinates
        .if     <cx a [bp].maxrow> near
            mov     cx,[bp].maxrow
        .endif
        test    bx,LVBPVB
        .if     <z>                     ; NOT LVB to PVB
            .if     <cx a es:[di].ScrlRectBottom> near
                mov     cx,es:[di].ScrlRectBottom
            .endif
        .endif

        mov     [bp].bottomscroll,cx
        mov     [bp].bottomdest,cx
        mov     [bp].bottomfill,cx

        .if     <ax a cx> near      ; rectangle is not valid
            mov     ax,ERROR_VIO_ROW
            jmp     sbrerr
        .endif

        mov     ax,[si].Col         ; set all of the left coordinates
        .if     <ax b [bp].mincol> near
            mov     ax,[bp].mincol
        .endif
                                        
        .if     <ax a [bp].maxcol> near 
            mov     ax,[bp].maxcol      
        .endif                          

        test    bx,LVBPVB
        .if     <z>                     ; NOT LVB to PVB
            .if     <ax b es:[di].ScrlRectLeft> near
                mov     ax,es:[di].ScrlRectLeft
            .endif

            .if     <ax a es:[di].ScrlRectRight> near
                mov     ax,es:[di].ScrlRectRight
            .endif
        .endif

        mov     [bp].leftscroll,ax
        mov     [bp].leftdest,ax
        mov     [bp].leftfill,ax

        mov     cx,[si].Col2        ; set all of the right coordinates
        .if     <cx a [bp].maxcol> near
            mov     cx,[bp].maxcol
        .endif
        test    bx,LVBPVB
        .if     <z>                     ; NOT LVB to PVB
            .if     <cx a es:[di].ScrlRectRight> near
                mov     cx,es:[di].ScrlRectRight
            .endif
        .endif
        mov     [bp].rightscroll,cx
        mov     [bp].rightdest,cx
        mov     [bp].rightfill,cx

        .if     <ax a cx> near      ; rectangle is not valid
            mov     ax,ERROR_VIO_COL
            jmp     sbrerr
        .endif

        cmp     ds:[si].ParmLength,LVBRowOff; Does caller want the touch rect?
        .if     <ae>                        ;   Yes, return the Touch Rect
            mov     ax,[bp].leftscroll
            mov     ds:[si].TouchXLeft,ax
            mov     ax,[bp].topscroll
            mov     ds:[si].TouchYTop,ax
            mov     ax,[bp].rightscroll
            mov     ds:[si].TouchXRight,ax
            mov     ax,[bp].bottomscroll
            mov     ds:[si].TouchYBottom,ax
        .endif

        mov     [bp].ScrollFlags, DOMOVE + DOFILL
        mov     cx, [si].RepeatFactor
        or      cx,cx               ; clears carry
        .if     <z>
            mov     [bp].ScrollFlags,cx ; do not Move or Fill
            xor     ax,ax           ; not an error not to scroll
            stc
        .endif

sbrx:   ret

sbrerr: stc
        jmp     sbrx

SetBaseRects    ENDP                                            ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = AdjustRects
;*
;* DESCRIPTION   = 
;*
;*      Adjust values for source, dest and fill rectangles
;*
;*      AdjustRects does scroll specific rectangle value setting for the
;*      source and destination rectangles for the rectangle that needs to
;*      be moved as part of the scroll.  Values for the fill rectangle are
;*      also adjusted.
;*
;*      This routine also checks and adjusts the RepeatFactor, the number
;*      of rows or columns to be scrolled.  If the value would clear the
;*      entire scroll rectangle, (no area left to be moved) the DOMOVE
;*      flag in the scroll flags is cleared.
;*
;*      If the repeat factor is larger than the depth of the scroll rectangle
;*      in the direction it is being scrolled, the repeat factor is reduced
;*      to the depth of the scroll rectangle.
;*
;*
;* INPUT    =   BX - Flag indicating the type of scroll (UP,DOWN,LEFT,RIGHT)
;*              CX = repeat factor
;*              SS:BP - local data storage area
;*              DS:SI - user passed parameter block
;*              ES:DI - mode data structure
;*              [bp].topscroll  - source rectangle for move set to
;*              [bp].leftscroll   default values
;*              [bp].rightscroll
;*              [bp].bottomscroll
;*              [bp].topdest    - destination rectangle for move set
;*              [bp].leftdest     to default values
;*              [bp].rightdest
;*              [bp].bottomdest
;*              [bp].topfill    - rectangle left void by move set to
;*              [bp].leftfill     default values
;*              [bp].rightfill
;*              [bp].bottomfill
;*
;* OUTPUT    =
;*              CX = repeat factor adjusted to MIN (rect depth,repeat factor)
;*              [bp].ScrollFlags  =  DOMOVE clear if entire rectangle is vacant
;*
;*              [bp].topfill      = Rectangle that the scroll leaves vacant
;*              [bp].leftfill     =     "
;*              [bp].rightfill    =     "
;*              [bp].bottomfill   =     "
;*
;*            if  DOMOVE is set
;*              [bp].topscroll    = Rect adjusted to indicate source of move
;*              [bp].leftscroll   =     "
;*              [bp].rightscroll  =     "
;*              [bp].bottomscroll =     "
;*
;*              [bp].topdest      = Rect adjusted to indicate dest of move
;*              [bp].leftdest     =     "
;*              [bp].rightdest    =     "
;*              [bp].bottomdest   =     "
;*
;* CALLS   none
;*
;* USES    AX,CX,FLAGS
;*
;* NOTES
;*
;* PSEUDOCODE
;*
;* UP:
;* DOWN:
;*     if (RepCount > bottomscroll - topscroll + 1)
;*         RepCount = bottomscroll - topscroll + 1
;*         DoMoveFlag = FALSE
;*     UP:
;*         topscroll = topscroll + RepCount
;*         bottomdest = bottomscroll - RepCount
;*         topfill = bottomdest + 1
;*     DOWN:
;*         bottomscroll = bottomscroll - RepCount
;*         topdest = topscroll + RepCount
;*         bottomfill = topdest - 1
;* LEFT:
;* RIGHT:
;*     if (RepCount > rightscroll - leftscroll + 1)
;*         RepCount = rightscroll - leftscroll + 1
;*         DoMoveFlag = FALSE
;*     LEFT:
;*         leftscroll = leftscroll + RepCount
;*         rightdest = rightscroll - RepCount
;*         leftfill = rightdest + 1
;*     RIGHT:
;*         rightscroll = rightscroll - RepCount
;*         leftdest = leftscroll + RepCount
;*         rightfill = leftdest - 1
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                PUBLIC  AdjustRects                             ;@P1 begin
AdjustRects     PROC
                                    ; correct coordinates for scroll type

        test    bx,UP+DOWN          ; Is this a scroll up or scroll down
        .if     <nz>                ;   Yes, do the up-down thing
            mov     ax,[bp].bottomscroll
            sub     ax,[bp].topscroll   ; (ax) = maximum possible scroll w/move
            .if     <cx a ax>
                and     [bp].ScrollFlags,NOT DOMOVE
                inc     ax          ; (ax) = scroll to clear entire rect
                mov     cx,ax       ; (cx) = maximum repcount
            .else
                test    bx,UP           ; Is this a scroll up?
                .if     <nz>            ;   Yes, do the up thing
                    add     [bp].topscroll,cx
                    mov     ax,[bp].bottomscroll
                    sub     ax,cx
                    mov     [bp].bottomdest,ax
                    inc     ax
                    mov     [bp].topfill,ax
                .else
                    sub     [bp].bottomscroll,cx
                    mov     ax,[bp].topscroll
                    add     ax,cx
                    mov     [bp].topdest,ax
                    dec     ax
                    mov     [bp].bottomfill,ax
                .endif
            .endif
        .else                           ; Do the left-right thing
            mov     ax,[bp].rightscroll
            sub     ax,[bp].leftscroll  ; (ax) = maximum possible scroll w/move
            .if     <cx a ax>
                and     [bp].ScrollFlags,NOT DOMOVE
                inc     ax              ; (ax) = scroll to clear entire rect
                mov     cx,ax           ; (cx) = maximum repcount
            .else
                test    bx,LEFT         ; Is this a scroll left?
                .if     <nz>            ;   Yes, do the left thing
                    add     [bp].leftscroll,cx
                    mov     ax,[bp].rightscroll
                    sub     ax,cx
                    mov     [bp].rightdest,ax
                    inc     ax
                    mov     [bp].leftfill,ax
                .else                   ; Do the Right thing
                    sub     [bp].rightscroll,cx
                    mov     ax,[bp].leftscroll
                    add     ax,cx
                    mov     [bp].leftdest,ax
                    dec     ax
                    mov     [bp].rightfill,ax
                .endif
            .endif
        .endif

        ret

AdjustRects     ENDP                                            ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = CalcMoveValues
;*
;* DESCRIPTION   = 
;*
;*      Calculate values the move rectangle functions need
;*
;*      CalcMoveValues calculates the offsets into the source and destination
;*      rectangles used by the move functions.  The UP and LEFT scroll
;*      functions copy from the beginning of the buffer to the end.  The
;*      DOWN and RIGHT functions copy from the end of the buffer to the
;*      beginning.  This function provides the correct starting point
;*      for the scroll requested.
;*
;*      This routine also calculates the number of rows that need to
;*      be copied.  This value will always be at least one.
;*
;*      The number of bytes in each row is calculated.  The value of
;*      this number is always at least one * cellsize (2 or 4 bytes)
;*      and is always a multiple of cell size.
;*
;*      The number of bytes that need to be skipped to reach the start
;*      of the next row to be copied is calculated.  This value may be
;*      zero.
;*
;*      With the exception of the number of rows to move, all of the
;*      values above are calculated separately for the LVB and the PVB
;*      because the cell size may be different between the two.
;*
;* INPUT    =   BX - Flag indicating the type of scroll (UP,DOWN,LEFT,RIGHT)
;*              SS:BP - local data storage area
;*              DS:SI - user passed parameter block
;*              ES:DI - mode data structure
;*              [bp].lvb_width - width of the LVB in cells
;*              [bp].cellsize - number of bytes per cell in the LVB
;*
;*              [bp].minrow - index of top most row in LVB (PVB coordinates)
;*              [bp].mincol - index of left most row in LVB (PVB coordinates)
;*              [bp].maxrow - index of bottom most row in LVB (PVB coordinates)
;*              [bp].maxcol - index of right most row in LVB (PVB coordinates)
;*
;*              [bp].topscroll    = Rect adjusted to indicate source of move
;*              [bp].leftscroll   =     "
;*              [bp].rightscroll  =     "
;*              [bp].bottomscroll =     "
;*
;*              [bp].topdest      = Rect adjusted to indicate dest of move
;*              [bp].leftdest     =     "
;*              [bp].rightdest    =     "
;*              [bp].bottomdest   =     "
;*
;* OUTPUT   =
;*              [bp].RowsToMove     = number of rows to move
;*
;*              [bp].PVBMoveCount   = # of bytes per PVB row to move
;*              [bp].PVBMoveSkip    = # of bytes to skip to get to the next row
;*              [bp].PVBMoveSrcOff  = offset to start of PVB source buffer
;*              [bp].PVBMoveDestOff = offset to start of PVB destination buffer
;*
;*              [bp].LVBMoveCount   = # of bytes per PVB row to move
;*              [bp].LVBMoveSkip    = # of bytes to skip to get to the next row
;*              [bp].LVBMoveSrcOff  = offset to start of PVB source buffer
;*              [bp].LVBMoveDestOff = offset to start of PVB destination buffer
;*
;* CALLS   none
;*
;* USES    AX,CX,DX,FLAGS
;*
;* NOTES
;*
;* PSEUDOCODE
;*
;*          RowsToMove = bottomscroll - topscroll + 1
;*          PVBMoveCount = (rightscroll - leftscroll) * cellsize
;*          PVBRowSkip = modeCols * cellsize - PVBMoveCount
;*          LVBMoveCount = (rightscroll - leftscroll) * cellsize
;*          LVBRowSkip = lvb_width * cellsize - LVBMoveCount
;*          UP:
;*          LEFT:
;*              LVBMoveSrcOff = ((topscroll - minrow) * lvb_width +
;*                               (leftscroll - mincol)) * cellsize
;*              PVBMoveSrcOff = (topscroll * modeCols + leftscroll) *
;*                              cellsize
;*              LVBMoveDestOff = ((topdest - minrow) * lvb_width +
;*                                (leftdest - mincol)) * cellsize
;*              PVBMoveDestOff = (topdest * modeCols + leftdest) *
;*                              cellsize
;*          DOWN:
;*          RIGHT:
;*              LVBMoveSrcOff = ((bottomscroll - minrow) * lvb_width +
;*                               (rightscroll - mincol)) * cellsize
;*              PVBMoveSrcOff = (bottomscroll * modeCols + rightscroll) *
;*                              cellsize
;*              LVBMoveDestOff = ((bottomdest - minrow) * lvb_width +
;*                                (rightdest - mincol)) * cellsize
;*              PVBMoveDestOff = (bottomdest * modeCols + rightdest) *
;*                              cellsize
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                    PUBLIC  CalcMoveValues                      ;@P1 begin
CalcMoveValues      PROC

        mov     ax,[bp].bottomscroll    ; calculate the number of rows
        sub     ax,[bp].topscroll       ; to move
        inc     ax
        mov     [bp].RowsToMove,ax

        mov     cx,[bp].rightscroll     ; calculate bytes to move in PVB
        sub     cx,[bp].leftscroll
        inc     cx
        shl     cx,1
        mov     [bp].PVBMoveCount,cx


        mov     ax,es:[di].TextCols     ; calculate bytes to skip in PVB
        shl     ax,1
        sub     ax,cx
        mov     [bp].PVBMoveSkip,ax

        mov     ax,[bp].lvb_width       ; calculate bytes to skip in LVB
        shl     ax,1
        sub     ax,cx
        .if     <[bp].cellsize e WorldCellSize>
            shl     cx,1
            shl     ax,1
        .endif
        mov     [bp].LVBMoveCount,cx    ; bytes to move in LVB
        mov     [bp].LVBMoveSkip,ax
                                        ; calculate buffer copy addresses
        test    bx,UP+LEFT
        .if     <nz>                    ; Do the UP-LEFT thing
            mov     ax,[bp].topscroll   ; calculate PVB source offset
            mul     es:[di].TextCols
            add     ax,[bp].leftscroll
            shl     ax,1
            mov     [bp].PVBMoveSrcOff,ax

            mov     ax,[bp].topdest     ; calculate PVB destination offset
            mul     [bp].lvb_width
            add     ax,[bp].leftdest
            shl     ax,1
            mov     [bp].PVBMoveDestOff,ax

            mov     ax,[bp].topscroll   ; calculate LVB source offset
            sub     ax,[bp].minrow
            mul     [bp].lvb_width
            add     ax,[bp].leftscroll
            sub     ax,[bp].mincol
            shl     ax,1                ; (ax) = LVB src off for 2 byte cell
            mov     [bp].LVBMoveSrcOff,ax

            mov     ax,[bp].topdest     ; calculate LVB destination offset
            sub     ax,[bp].minrow
            mul     [bp].lvb_width
            add     ax,[bp].leftdest
            sub     ax,[bp].mincol
            shl     ax,1                ; (cx)= LVB dest off for 2 byte cell
            mov     [bp].LVBMoveDestOff,ax

            .if     <[bp].cellsize e WorldCellSize>
                shl     [bp].LVBMoveSrcOff,1    ; 4 bytes per cell
                shl     [bp].LVBMoveDestOff,1   ; 4 bytes per cell
            .endif

        .else                           ; Do the DOWN-RIGHT thing
            mov     ax,[bp].bottomscroll; calculate PVB source offset
            mul     es:[di].TextCols
            add     ax,[bp].rightscroll
            shl     ax,1
            mov     [bp].PVBMoveSrcOff,ax

            mov     ax,[bp].bottomdest  ; calculate PVB destination offset
            mul     [bp].lvb_width
            add     ax,[bp].rightdest
            shl     ax,1
            mov     [bp].PVBMoveDestOff,ax

            mov     ax,[bp].bottomscroll; calculate LVB source offset
            sub     ax,[bp].minrow
            mul     [bp].lvb_width
            add     ax,[bp].rightscroll
            sub     ax,[bp].mincol
            shl     ax,1                ; (ax) = LVB src off for 2 byte cell
            mov     [bp].LVBMoveSrcOff,ax

            mov     ax,[bp].bottomdest  ; calculate LVB destination offset
            sub     ax,[bp].minrow
            mul     [bp].lvb_width
            add     ax,[bp].rightdest
            sub     ax,[bp].mincol
            shl     ax,1                ; (cx)= LVB dest off for 2 byte cell
            mov     [bp].LVBMoveDestOff,ax
            .if     <[bp].cellsize e WorldCellSize>
                inc     [bp].LVBMoveSrcOff  ; start at last word of cell
                inc     [bp].LVBMoveDestOff ; start at last word of cell
                shl     [bp].LVBMoveSrcOff,1    ; 4 bytes per cell
                shl     [bp].LVBMoveDestOff,1   ; 4 bytes per cell
            .endif

        .endif
        ret

CalcMoveValues      ENDP                                        ;@P1 end

;/***************************************************************************
;*
;* FUNCTION NAME = CalcFillValues
;*
;* DESCRIPTION   = 
;*
;*      Calculate values the fill rectangle function needs
;*
;*      CalcFillValues calculates the offset into the fill rectangle that
;*      is used by the fill function.
;*
;*      This routine also calculates the number of rows that need to
;*      be filled.  This value will always be at least one.
;*
;*      The number of bytes in each row is calculated.  The value of
;*      this number is always at least one * cellsize (2 or 4 bytes)
;*      and is always a multiple of cell size.
;*
;*      The number of bytes that need to be skipped to reach the start
;*      of the next row to be copied is calculated.  This value may be
;*      zero.
;*
;*      With the exception of the number of rows to move, all of the
;*      values above are calculated separately for the LVB and the PVB
;*      because the cell size may be different between the two.
;*
;* INPUT    =   BX - Flag indicating the type of scroll (UP,DOWN,LEFT,RIGHT)
;*              SS:BP - local data storage area
;*              DS:SI - user passed parameter block
;*              ES:DI - mode data structure
;*              [bp].lvb_width - width of the LVB in cells
;*              [bp].cellsize - number of bytes per cell in the LVB
;*
;*              [bp].minrow - index of top most row in LVB (PVB coordinates)
;*              [bp].mincol - index of left most row in LVB (PVB coordinates)
;*
;*              [bp].topfill      = Rect adjusted to indicate fill region
;*              [bp].leftfill     =     "
;*              [bp].rightfill    =     "
;*              [bp].bottomfill   =     "
;*
;* OUTPUT   =
;*              [bp].RowsToFill   = rows to be filled with the default cell
;*
;*              [bp].PVBFillCount = # of bytes per fill line in PVB
;*              [bp].PVBFillSkip  = # of bytes to skip to reach next PVB line
;*              [bp].PVBFillOff   = offset of beginning of PVB fill rectangle
;*
;*              [bp].LVBFillCount = # of bytes per fill line in LVB
;*              [bp].LVBFillSkip  = # of bytes to skip to reach next LVB line
;*              [bp].LVBFillOff   = offset of beginning of LVB fill rectangle
;*
;*              [bp].FillCellLow  = first word of default fill cell
;*              [bp].FillCellHigh = second word of default fill cell
;*
;* CALLS   none
;*
;* USES    AX,CX,DX,SI,FLAGS
;*
;* NOTES
;*
;* PSEUDOCODE
;*
;*       RowsToFill = bottomfill - topfill + 1
;*       PVBFillOff = (topfill * modeCols + leftfill) * cellsize
;*       PVBFillCount = rightfill - leftfill * cellsize
;*       PVBFillSkip = modeCols * cellsize - PVBFillCount
;*       LVBFillOff = (leftfill - minrow) * lvb_width +
;*                    (topfill - mincol) * cellsize
;*       LVBFillCount = rightfill - leftfill * cellsize
;*       LVBFillSkip = modeCols * cellsize - LVBFillCount
;*       FillCellLow = first word of cell
;*       if (inputcellsize = 4)
;*           FillCellHigh = second word of cell
;*       else
;*           FillCellHigh = 0
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                    PUBLIC  CalcFillValues                      ;@P1 begin
CalcFillValues      PROC

        mov     ax,[bp].bottomfill      ; calculate the number of rows
        sub     ax,[bp].topfill         ; to fill
        inc     ax
        mov     [bp].RowsToFill,ax

        mov     ax,[bp].topfill         ; calculate PVB source offset
        mul     es:[di].TextCols
        add     ax,[bp].leftfill
        shl     ax,1
        mov     [bp].PVBFillOff,ax

        mov     cx,[bp].rightfill       ; calculate byte per PVB fill row
        sub     cx,[bp].leftfill
        inc     cx
        shl     cx,1
        mov     [bp].PVBFillCount,cx

        mov     ax,es:[di].TextCols     ; calculate bytes to skip in PVB
        shl     ax,1
        sub     ax,cx
        mov     [bp].PVBFillSkip,ax

        mov     ax,[bp].lvb_width       ; calculate bytes to skip in LVB
        shl     ax,1
        sub     ax,cx
        .if     <[bp].cellsize e WorldCellSize>
            shl     cx,1
            shl     ax,1
        .endif
        mov     [bp].LVBFillCount,cx    ; bytes to fill in LVB
        mov     [bp].LVBFillSkip,ax

        mov     ax,[bp].topfill         ; calculate LVB source offset
        sub     ax,[bp].minrow
        mul     [bp].lvb_width
        add     ax,[bp].leftfill
        sub     ax,[bp].mincol
        shl     ax,1

        .if     <[bp].cellsize e WorldCellSize>
            shl     ax,1
        .endif
        mov     [bp].LVBFillOff,ax

        test    bx,LVBPVB
        .if     <z>
            test    [si].Flags,CGAAttr      ; the jump is 5 lines down

            lds     si,[si].AppCellAddr
            lodsw
            mov     [bp].FillCellLow,ax
            mov     [bp].FillCellHigh,0

            .if     <z> and
            .if     <[bp].cellsize e WorldCellSize>
                lodsw
                mov     [bp].FillCellHigh,ax
            .endif
            lds     si,[bp].ParmBuf         ; (ds:si) -> parameter buffer
        .endif

        ret

CalcFillValues      ENDP                                        ;@P1 end
 

;/***************************************************************************
;*
;* FUNCTION NAME = MoveUpLeft
;*
;* DESCRIPTION   = 
;*
;*      Move a rectangle for ScrollUp or ScrollLeft
;*
;*      MoveUpLeft copys a rectangle in the LVB and/or PVB from beginning
;*      to end, one line at a time.
;*
;* INPUT     =  BX = LVB selector or 0 if no LVB write indicated
;*              SS:BP - local data storage area
;*
;*              [bp].PVB_Sel = PVB selector if PVB scroll is indicated else 0
;*
;*              [bp].RowsToMove     = number of rows to move
;*
;*              [bp].PVBMoveCount   = # of bytes per PVB row to move
;*              [bp].PVBMoveSkip    = # of bytes to skip to get to the next row
;*              [bp].PVBMoveSrcOff  = offset to start of PVB source buffer
;*              [bp].PVBMoveDestOff = offset to start of PVB destination buffer
;*
;*              [bp].LVBMoveCount   = # of bytes per PVB row to move
;*              [bp].LVBMoveSkip    = # of bytes to skip to get to the next row
;*              [bp].LVBMoveSrcOff  = offset to start of PVB source buffer
;*              [bp].LVBMoveDestOff = offset to start of PVB destination buffer
;*
;* OUTPUT    =
;*              The rectangle in the LVB or PVB is moved as appropriate
;*
;* CALLS   none
;*
;* USES    AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* NOTES
;*
;* PSEUDOCODE
;*
;*        cursrcoff  = FirstMoveSrcOff
;*        curdestoff  = FirstMoveDestOff
;*        while (RowsToMove--)
;*            curcount = MoveCount
;*            while (curcount--)
;*                *curdestoff++ = *cursrcoff++
;*            cursrcoff += NextLineMove
;*            curdestoff += NextLineMove
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                PUBLIC  MoveUpLeft                              ;@P1 begin
MoveUpLeft      PROC

        cld                                 ; increment si, di
        .if     <nonzero bx>
            mov     ds,bx
            mov     es,bx
            mov     bx,[bp].RowsToMove
            mov     si,[bp].LVBMoveSrcOff
            mov     di,[bp].LVBMoveDestOff
            mov     dx,[bp].LVBMoveCount
            shr     dx,1                    ; convert bytes to words

mulf10:     mov     cx,dx                   ; (cx) = bytes to move this row
IFDEF D1348 ;check if DBCS && common lvb.
            .if    <bit <[bp].flgDBCS> and anyDBCS> and
            .if    <[bp].j_funcindx eq WorldFmtIndx>
                push    bx                  ; save row count
                call    MoveUpLeftWrld
                pop     bx                  ; restore row count
            .else
                rep     movsw               ; move the line
            .endif
ELSE  ;D1348
            rep     movsw                   ; move the line
ENDIF ;D1348
            add     si,[bp].LVBMoveSkip     ; advance to the next source line
            add     di,[bp].LVBMoveSkip     ; advance to the next dest line
            dec     bx                      ; Are there more rows to move?
            jnz     mulf10                  ;   Yes, go do the next one

        .endif
        mov     bx,[bp].PVB_SEL
        .if     <nonzero bx>
            mov     ds,bx
            mov     es,bx
            mov     bx,[bp].RowsToMove
            mov     si,[bp].PVBMoveSrcOff
            mov     di,[bp].PVBMoveDestOff
            mov     dx,[bp].PVBMoveCount
            shr     dx,1                    ; convert bytes to words

mulf20:     mov     cx,dx                   ; (cx) = bytes to move this row
            REP_MOVSW                       ; Use this macro so CGA can share
                                            ; the same set of sources
            add     si,[bp].PVBMoveSkip     ; advance to the next source line
            add     di,[bp].PVBMoveSkip     ; advance to the next dest line
            dec     bx                      ; Are there more rows to move?
            jnz     mulf20                  ;   Yes, go do the next one

        .endif

        ret

MoveUpLeft      ENDP                                            ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = MoveDownRight
;*
;* DESCRIPTION   = 
;*
;*      Move a rectangle for ScrollDown or ScrollRight
;*
;*      MoveDownRight copys a rectangle in the LVB and/or PVB from beginning
;*      to end, one line at a time.
;*
;* INPUT     =  BX = LVB selector or 0 if no LVB write indicated
;*              SS:BP - local data storage area
;*
;*              [bp].PVB_Sel = PVB selector if PVB scroll is indicated else 0
;*
;*              [bp].RowsToMove     = number of rows to move
;*
;*              [bp].PVBMoveCount   = # of bytes per PVB row to move
;*              [bp].PVBMoveSkip    = # of bytes to skip to get to the next row
;*              [bp].PVBMoveSrcOff  = offset to start of PVB source buffer
;*              [bp].PVBMoveDestOff = offset to start of PVB destination buffer
;*
;*              [bp].LVBMoveCount   = # of bytes per PVB row to move
;*              [bp].LVBMoveSkip    = # of bytes to skip to get to the next row
;*              [bp].LVBMoveSrcOff  = offset to start of PVB source buffer
;*              [bp].LVBMoveDestOff = offset to start of PVB destination buffer
;*
;* OUTPUT    =
;*              The rectangle in the LVB or PVB is moved as appropriate
;*
;* CALLS   none
;*
;* USES    AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;* NOTES
;*
;* PSEUDOCODE
;*
;*        cursrcoff  = LastMoveSrcOff
;*        curdestoff  = LastMoveDestOff
;*        while (RowsToMove--)
;*            curcount = MoveCount
;*            while (curcount--)
;*                *curdestoff-- = *cursrcoff--
;*            cursrcoff -= NextLineMove
;*            curdestoff -= NextLineMove
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                PUBLIC  MoveDownRight                           ;@P1 begin
MoveDownRight   PROC

        std                                 ; decrement si, di
        .if     <nonzero bx>
            mov     ds,bx
            mov     es,bx
            mov     bx,[bp].RowsToMove
            mov     si,[bp].LVBMoveSrcOff
            mov     di,[bp].LVBMoveDestOff
            mov     dx,[bp].LVBMoveCount
            shr     dx,1                    ; convert bytes to words

mdrt10:     mov     cx,dx                   ; (cx) = bytes to move this row
IFDEF D1348 ;check if DBCS && common lvb.
            .if    <bit <[bp].flgDBCS> and anyDBCS> and
            .if    <[bp].j_funcindx eq WorldFmtIndx>
                push    bx                  ; save row count
                call    MoveDownRightWrld
                pop     bx                  ; restore row count
            .else
                rep     movsw               ; move the line
            .endif
ELSE  ;D1348
            rep     movsw                   ; move the line
ENDIF ;D1348
            sub     si,[bp].LVBMoveSkip     ; advance to the next source line
            sub     di,[bp].LVBMoveSkip     ; advance to the next dest line
            dec     bx                      ; Are there more rows to move?
            jnz     mdrt10                  ;   Yes, go do the next one

        .endif
        mov     bx,[bp].PVB_SEL
        .if     <nonzero bx>
            mov     ds,bx
            mov     es,bx
            mov     bx,[bp].RowsToMove
            mov     si,[bp].PVBMoveSrcOff
            mov     di,[bp].PVBMoveDestOff
            mov     dx,[bp].PVBMoveCount
            shr     dx,1                    ; convert bytes to words

mdrt20:     mov     cx,dx                   ; (cx) = bytes to move this row
            REP_MOVSW                       ; Use this macro so CGA can share
                                            ; the same set of sources
            sub     si,[bp].PVBMoveSkip     ; advance to the next source line
            sub     di,[bp].PVBMoveSkip     ; advance to the next dest line
            dec     bx                      ; Are there more rows to move?
            jnz     mdrt20                  ;   Yes, go do the next one

        .endif

        ret

MoveDownRight   ENDP                                            ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = FillRectWithCell
;*
;* DESCRIPTION   = 
;*
;*      Fill a rectangle for with the default cell
;*
;*      FillRectWithCell fills the specified rectangle in the LVB and/or
;*      PVB with the given cell, beginning to end, one line at a time.
;*
;* INPUT     =  BX = LVB selector or 0 if no LVB write indicated
;*              SS:BP - local data storage area
;*
;*              [bp].PVB_Sel = PVB selector if PVB scroll is indicated else 0
;*
;*              [bp].RowsToFill   = rows to be filled with the default cell
;*
;*              [bp].PVBFillCount = # of bytes per fill line in PVB
;*              [bp].PVBFillSkip  = # of bytes to skip to reach next PVB line
;*              [bp].PVBFillOff   = offset of beginning of PVB fill rectangle
;*
;*              [bp].LVBFillCount = # of bytes per fill line in LVB
;*              [bp].LVBFillSkip  = # of bytes to skip to reach next LVB line
;*              [bp].LVBFillOff   = offset of beginning of LVB fill rectangle
;*
;*              [bp].FillCellLow  = first word of default fill cell
;*              [bp].FillCellHigh = second word of default fill cell
;*
;* OUTPUT     =
;*              The rectangle in the LVB or PVB is moved as appropriate
;*
;*
;*      CALLS   none
;*
;*      USES    AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;*      NOTES
;*
;*      PSEUDOCODE
;*
;*           curdestoff = FirstFillDestOff
;*           while (RowsToFill)
;*           for (curline = FirstFillLine; curline <= LastFillLine; curline++)
;*               curcount = FillCount
;*               while (curcount--)
;*                   *curdestoff = fillcell
;*               curdestoff += NextLineFill
;*
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                PUBLIC  FillRectWithCell                        ;@P1 begin
FillRectWithCell    PROC

        cld                                 ; increment si, di
        mov     ax,[bp].FillCellLow
        .if     <nonzero bx>
            mov     ds,bx
            mov     es,bx
            mov     bx,[bp].RowsToFill
            mov     di,[bp].LVBFillOff
            mov     dx,[bp].LVBFillCount
            .if     <[bp].cellsize e WorldCellSize>
                mov     si,[bp].FillCellHigh
                shr     dx,2                ; convert bytes to cells

frwc10:         mov     cx,dx               ; (cx) = bytes to move this row
                .repeat                     ; fill the line with the cell
                    stosw
                    xchg    ax,si
                    stosw
                    xchg    ax,si
                .loop
                add     di,[bp].LVBFillSkip ; advance to the next source line
                dec     bx                  ; Are there more rows to move?
                jnz     frwc10              ;   Yes, go do the next one
            .else
                shr     dx,1                ; convert bytes to cells

frwc20:         mov     cx,dx               ; (cx) = bytes to move this row
                rep     stosw               ; fill the line with the cell
                add     di,[bp].LVBFillSkip ; advance to the next source line
                dec     bx                  ; Are there more rows to move?
                jnz     frwc20              ;   Yes, go do the next one
            .endif
        .endif
        mov     bx,[bp].PVB_SEL
        .if     <nonzero bx>
            mov     ds,bx
            mov     es,bx
            mov     bx,[bp].RowsToFill
            mov     di,[bp].PVBFillOff
            mov     dx,[bp].PVBFillCount
            shr     dx,1                    ; convert bytes to words

frwc30:     mov     cx,dx                   ; (cx) = bytes to move this row
            REP_STOSW                       ; Use this macro so CGA can share
                                            ; the same set of sources
            add     di,[bp].PVBFillSkip     ; advance to the next dest line
            dec     bx                      ; Are there more rows to move?
            jnz     frwc30                  ;   Yes, go do the next one
        .endif

        ret

FillRectWithCell    ENDP                                        ;@P1 end


;/***************************************************************************
;*
;* FUNCTION NAME = MoveLVBRectToPVB
;*
;*      Copy a rectangle from LVB to PVB
;*
;*      MoveLVBRectToPVB copys the FillRect in the LVB to the FillRect in
;*      the PVB.  Conversions for different cell sizes are done at this time.
;*
;* INPUT    =   BX = LVB selector or 0 if no LVB write indicated
;*              SS:BP - local data storage area
;*
;*              [bp].PVB_Sel = PVB selector if PVB scroll is indicated else 0
;*
;*              [bp].RowsToFill   = rows to be filled with the default cell
;*
;*              [bp].PVBFillCount = # of bytes per fill line in PVB
;*              [bp].PVBFillSkip  = # of bytes to skip to reach next PVB line
;*              [bp].PVBFillOff   = offset of beginning of PVB fill rectangle
;*
;*              [bp].LVBFillCount = # of bytes per fill line in LVB
;*              [bp].LVBFillSkip  = # of bytes to skip to reach next LVB line
;*              [bp].LVBFillOff   = offset of beginning of LVB fill rectangle
;*
;*              [bp].FillCellLow  = first word of default fill cell
;*              [bp].FillCellHigh = second word of default fill cell
;*
;* OUTPUT    =
;*              The rectangle in the LVB or PVB is moved as appropriate
;*
;*
;*      CALLS   none
;*
;*      USES    AX,BX,CX,DX,SI,DI,DS,ES,FLAGS
;*
;*      NOTES
;*
;*      PSEUDOCODE
;*
;*          cursrcoff = LVBFillOff
;*          curdestoff = PVBFillOff
;*          while (RowsToFill)
;*              curcount = FillCount
;*              while (curcount--)
;*                  *curdestoff = *cursrcoff
;*              curdestoff += PVBFillSkip
;*              cursrcoff += LVBFillSkip
;*        
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;****************************************************************************/

                PUBLIC  MoveLVBRectToPVB                        ;@P1 begin
MoveLVBRectToPVB    PROC

        cld                                 ; increment si, di
        .if     <nonzero bx> and
        mov     ds,bx                       ; (ds) = LVB segment
        mov     bx,[bp].PVB_Sel
        .if     <nonzero bx>
            mov     es,bx                   ; (es) = PVB segment
            mov     si,[bp].LVBFillOff      ; (si) = LVB rectangle offset
            mov     di,[bp].PVBFillOff      ; (di) = PVB rectangle offset
            mov     bx,[bp].RowsToFill
            mov     dx,[bp].LVBFillCount
            .if     <[bp].cellsize e WorldCellSize>
                shr     dx,2                ; convert bytes to cells

lrtp10:         mov     cx,dx               ; (cx) = bytes to move this row
                REP_MOVSW_ADDSI2_LOOP       ; Use this macro so CGA can share
                                            ; the same set of sources
                add     si,[bp].LVBFillSkip ; advance to the next LVB line
                add     di,[bp].PVBFillSkip ; advance to the next PVB line
                dec     bx                  ; Are there more rows to move?
                jnz     lrtp10              ;   Yes, go do the next one
            .else
                shr     dx,1                ; convert bytes to cells

lrtp20:         mov     cx,dx               ; (cx) = bytes to move this row
                REP_MOVSW                   ; Use this macro so CGA can share
                                            ; the same set of sources
                add     si,[bp].LVBFillSkip ; advance to the next LVB line
                add     di,[bp].PVBFillSkip ; advance to the next PVB line
                dec     bx                  ; Are there more rows to move?
                jnz     lrtp20              ;   Yes, go do the next one
            .endif
        .endif

        ret

MoveLVBRectToPVB    ENDP                                        ;@P1 end

R2CSEG  ENDS
        END

