
;************************************************************************
; Scrolling 80 column page of text                                      *
; Entry:        Count           - Number of lines to scroll             *
;************************************************************************

Count   EQU     WORD PTR [BP+4]

        PUBLIC  _Scroll_Page

_Scroll_Page     PROC NEAR
        PUSH    BP
        MOV     BP,SP

        ;--- Determine and load segement of the display buffer

        PUSH    DS                      ;Preserve registers
        PUSH    ES
        PUSH    SI
        PUSH    DI

        XOR     AX,AX                   ;Point ES to segment zero
        MOV     ES,AX
        MOV     AX,0B000H               ;Assume monochrome buffer address
        TEST    BYTE PTR ES:[BIOS_Equipment],2   ;Is mono attached?
        JNZ     PAddr_Ok                ;...Yes, go load segment
        MOV     AX,0B800H               ;...No, change address to color
PAddr_Ok:
        MOV     DS,AX                   ;Set segment of display buffer

        ;--- Compute pointers to source and destination

        CMP     Count,0                 ;Are we scrolling up?
        JL      P_Set_Down              ;...No, setup for scrolling down
P_Set_Up:
        MOV     BX,ES:[BIOS_Columns]    ;Fetch number of columns
        MOV     AX,Count                ;Fetch number of rows to scroll
        MUL     BX                      ;Compute address of first byte to
        SHL     AX,1                    ;move as Columns*Count*2
        MOV     SI,AX                   ;Save address of first byte to move
        XOR     DI,DI                   ;Address of where to move to
        MOV     AL,ES:[BIOS_Rows]       ;Number of bytes to move is
        XOR     AH,AH
        SUB     AX,Count                ;(Total_Rows-Count)*Columns*2
        MUL     BX                      ;multiply rows*columns
        SHL     AX,1                    ;multipy by 2 (account for attrib)
        MOV     CX,AX                   ;Move count into register CX
        MOV     AX,DS                   ;Point segment register ES to
        MOV     ES,AX                   ;the display buffer segment
        REP     MOVSB                   ;Move rows up
P_Clear_Up:
        MOV     AX,Count                ;Compute number of words to clear
        MUL     BX                      ;as Rows*Columns
        MOV     CX,AX                   ;Save the count in register CX
        MOV     AX,0700H+' '            ;Value to use in 'cleared' area
                                        ;is attribute 7 and character ' '
        REP     STOSW                   ;'Clear' the area
        JMP     Page_Scroll_Done

P_Set_Down:
        MOV     BX,ES:[BIOS_Columns]    ;Fetch number of columns
        MOV     AL,ES:[BIOS_Rows]       ;Fetch total number of rows
        XOR     AH,AH
        SUB     AX,Count                ;Compue address of first byte
        MUL     BX                      ;to move as Total Rows - Count *
        DEC     AX                      ;* Columns * 2 - 2
        SHL     AX,1
        MOV     SI,AX                   ;Save address of first byte to move

        MOV     AL,ES:[BIOS_Rows]       ;Fetch total number of rows
        XOR     AH,AH
        MUL     BX                      ;Compute address of first byte of
        DEC     AX                      ;where the to move bytes to as
        SHL     AX,1                    ;(Total Rows * Columns - 1) * 2
        MOV     DI,AX                   ;Save address in register DI

        MOV     AL,ES:[BIOS_Rows]       ;Compute number of byte to
        XOR     AH,AH
        SUB     AX,Count                ;move as
        MUL     BX                      ;(Total Rows - Count) * Columns * 2
        SHL     AX,1
        MOV     CX,AX                   ;Put count into register CX
        STD                             ;Set direction flag to 'decrement'
        REP     MOVSB                   ;Move rows up

P_Clear_Down:
        MOV     AX,Count                ;Compute number of words to clear
        MUL     BX                      ;as Rows*Columns
        MOV     CX,AX                   ;Save the count in register CX
        MOV     AX,0700H+' '            ;Value to use in 'cleared' area
                                        ;is attribute 7 and character ' '
        REP     STOSW                   ;'Clear' the area
        CLD                             ;Reset the direction flag

Page_Scroll_Done:
        POP     DI
        POP     SI
        POP     ES
        POP     DS

        POP     BP
        RET
_Scroll_Page    ENDP
