
;************************************************************************
; Smooth vertical scroll                                                *
; Assumes that line width is set correctly in the BIOS data area        *
; Entry:        Y_Offset- Current vertical offset                       *
;************************************************************************

Y_Offset        EQU     [BP+4]

        PUBLIC  _Vertical_Scroll

_Vertical_Scroll PROC    NEAR
        PUSH    BP                      ;Standard entry from high level
        MOV     BP,SP
        PUSH    ES

        XOR     AX,AX                   ;Point ES to segment zero
        MOV     ES,AX

        ;--- Wait for an end of vertical retrace

        MOV     DX,ES:[BIOS_CRT_Addr]   ;Get address of CRT controller
        ADD     DX,6                    ;Wait for retrace to change registers
VS_Wait1:                               ;Wait for vertical to start
        IN      AL,DX
        JMP     $+2
        TEST    AL,8
        JZ      VS_Wait1
VS_Wait2:                               ;Wait for vertical to end
        IN      AL,DX
        JMP     $+2
        TEST    AL,8
        JNZ     VS_Wait2

        ;--- Set CRTC ADDRESS register to (columns * offset / char_height)

        MOV     AX,Y_Offset             ;Fetch new Y
        XOR     DX,DX                   ;Clear DX for divide
        MOV     BX,ES:[BIOS_Height]     ;Get character height
        DIV     BX                      ;Divide offset by character height
        MOV     BX,AX                   ;Save number of text lines to skip
        MOV     CX,DX                   ;Save number of scan lines to skip
        MOV     AX,ES:[BIOS_Columns]    ;Fetch number of bytes per text line
        MUL     BX                      ;Compute number of bytes to skip
        MOV     BX,AX                   ;Save it in BX
        MOV     DX,ES:[BIOS_CRT_Addr]   ;Get address of CRT controller
        MOV     AL,0DH                  ;Index for START ADDRESS register LO
        OUT     DX,AL                   ;Select index
        INC     DX
        MOV     AL,BL                   ;Fetch the scroll value we computed
        OUT     DX,AL                   ;Set START register
        DEC     DX
        MOV     AL,0CH                  ;Write the high byte of the start addr
        OUT     DX,AL
        INC     DX
        MOV     AL,BH
        OUT     DX,AL
        DEC     DX

        ;--- Set CRTC PRESET ROW SCAN register to number of scan lines to skip

        ADD     DX,6
VS_Wait3:                               ;Wait for vertical to start
        IN      AL,DX
        JMP     $+2
        TEST    AL,8
        JZ      VS_Wait3
        SUB     DX,6

        MOV     AL,8                    ;Index of PRESET ROW SCAN register
        OUT     DX,AL                   ;Select PRESET ROW SCAN register
        MOV     AL,CL                   ;Fetch scan lines to skip
        INC     DX
        OUT     DX,AL                   ;Set PRESET ROW SCAN register

        POP     ES
        MOV     SP,BP
        POP     BP
        RET
_Vertical_Scroll ENDP
