
;************************************************************************
;                                                                       *
;  Scanline(start, end, raster, color):draw line from (start,y) to      *
;       (end,y) with a color 'color'.                                   *
;  Entry :sp + 2 = Start                                                *
;         sp + 4 = Stop                                                 *
;         sp + 6 = y                                                    *
;         sp + 8 = color                                                *
;               ....                                                    *
;                                                                       *
;************************************************************************

XSIZE   EQU     640
HBYTES  EQU     (XSIZE/8)
GRFSEG  EQU     0A000H

Start   EQU     [BP+4]
Stop    EQU     [BP+6]
Raster  EQU     [BP+8]
Color   EQU     [BP+10]

        PUBLIC  _ScanLine

_ScanLine       PROC NEAR
        PUSH    BP
        MOV     BP,SP

        PUSH    DI                      ;Preserve segment registers
        PUSH    SI
        PUSH    DS
        PUSH    ES

       ;--- Load SET/RESET registers with current color

        MOV     DX,03CEh                ; move color into reset register
        XOR     AL,AL
        OUT     DX,AL
        INC     DX
        MOV     AL,Color
        OUT     DX,AL
        DEC     DX                      ; enable use of reset register
        MOV     AL,1
        OUT     DX,AL
        INC     DX
        MOV     AL,0Fh
        OUT     DX,AL
        MOV     DX,03C4h                ; enable all four planes for writing
        MOV     AL,2
        OUT     DX,AL
        INC     DX
        MOV     AL,0Fh
        OUT     DX,al

        ;--- COMPUTE ADDRESS AND MASK FOR FIRST PIXEL -------------
SL_Address:
        ;--- Convert (x,y) to absolute address in display buffer

        MOV     AX,Raster               ;Compute offset as 80*y+x/8
        MOV     BX,HBYTES
        MUL     BX
        MOV     DI,Start                ; + x/8
        MOV     CL,3
        SHR     DI,CL
        ADD     DI,AX

        MOV     DX,GRFSEG               ;Point DS and ES into display buffer
        MOV     DS,DX
        MOV     ES,DX

        MOV     CX,Stop                 ;Compute dx
        SUB     CX,Start

        ;--- Compute bit mask for the leading partial byte

        MOV     AX,Start                ;Fetch x0
        AND     AX,07H                  ;Check if there is leading partial byte
        JZ      SL_Complete             ;...No, bypass this step
        MOV     BX,0FFH                 ;Compute mask for the first byte by
        PUSH    CX                      ;shifting FF pattern to the right
        MOV     CX,AX                   ;until only partial leading bits are
        SHR     BX,CL                   ;on
        POP     CX
        ADD     CX,AX                   ;Update counter of bits completed
        SUB     CX,8
        JGE     SL_SetMask              ;Modify mask if only one byte
        NEG     CX
        SHR     BX,CL
        SHL     BX,CL
        XOR     CX,CX                   ; restore counter
SL_SetMask:
        MOV     DX,3CEH                 ;Set mask by loading BIT MASK
        MOV     AL,08h                  ;register in the GRAPHICS controller
        OUT     DX,AL
        INC     DX
        MOV     AL,BL
        OUT     DX,AL

        ;--- Draw pixels from the leading partial byte

        MOV     AL,[DI]                 ;Latch data
        STOSB                           ;Write new data

        ;--- Draw pixels from the middle complete bytes

SL_Complete:                            ; check if any bytes to set
        MOV     BX,CX                   ;Check if there is more than 7 bits
        CMP     CX,8                    ;left to draw
        JL      SL_Trailing             ;... If not, skip this part

        SHR     CX,1                    ;Divide bits by 8 to get byte count
        SHR     CX,1
        SHR     CX,1
        MOV     DX,03CEH                ; Enable all 8 bits for write
        MOV     AL,08h                  ; by writing to BIT MASK register in
        OUT     DX,AL                   ; the SEQUENCER
        INC     DX
        MOV     AL,0FFH
        OUT     DX,AL

        REP     STOSB                   ;Write new data

        ;--- Compute mask for the trailing partial byte

SL_Trailing:
        AND     BX,07H                  ;Check if there are any bits left to do
        JZ      SL_Done                 ;...No, quit
        MOV     AX,0FFFFH               ;...Yes, compute mask by shifting FFFF
        MOV     CX,BX                   ;by number of bits to be drawn
        SHR     AX,CL
        XOR     AH,0FFH
        MOV     DX,03CEH                ;Set BIT MASK register in GRAPHICS
        MOV     AL,08h                  ;controller to the mask
        OUT     DX,AL
        INC     DX
        MOV     AL,AH
        OUT     DX,AL

        ;--- Draw pixels from the trailing partial byte

        MOV     AL,[DI]                 ;Latch data
        STOSB                           ;Write new data

        ;--- Restore PLANE ENABLE and BIT MASK registers
SL_Done:
        MOV     DX,03CEh                ; Enable all 8-bits in a byte for write
        MOV     AL,08h                  ; by setting BIT MASK register to Fhex
        OUT     DX,AL
        INC     DX
        MOV     AL,0FFh
        OUT     DX,AL

        DEC     DX                      ; Disable SET/RESET function
        MOV     AL,1
        OUT     DX,AL
        INC     DX
        XOR     AX,AX
        OUT     DX,AL

        POP     ES                      ;Restore segment registers
        POP     DS
        POP     SI
        POP     DI
        MOV     SP,BP
        POP     BP
        RET
_ScanLine       ENDP
