
;************************************************************************
; Common definitions for the next five routines                         *
;************************************************************************

GRAPHICS_CTL    EQU     3CEH            ;Address of Graphics controller
SEQUENCE_CTL    EQU     3C4H            ;Address the Sequencer

XSIZE   EQU     640                     ;Assume 640 pixels across
HBYTES  EQU     (XSIZE/8)               ;Compute bytes per raster
GRAPH_SEG       EQU     0A000H          ;Segment of display buffer

;************************************************************************
; Set pixel at X,Y to color COLOR                                       *
; using SET-RESET method                                                *
;************************************************************************

X               EQU     [BP+4]          ;Formal parameters on stack
Y               EQU     [BP+6]
COLOR           EQU     [BP+8]

        PUBLIC  _Pixel_Set

_Pixel_Set      PROC    NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    ES

        ; Convert x,y address into OFFSET:SEGMENT and get MASK

        MOV     BX,X                    ;Fetch X coordinate
        MOV     AX,Y                    ;Fetch Y coordinate
        CALL    Get_Address             ;Compute SEGMENT:OFFSET address
                                        ;in ES:BX, Mask in CL

        MOV     DX,GRAPHICS_CTL

        ; Enable set/reset and load value into reset register

        MOV     AL,00H                  ;Select SET/RESET register
        OUT     DX,AL
        INC     DX
        MOV     AL,COLOR                ;Fetch color passed on the stack
        OUT     DX,AL                   ;Set SET register to color
        DEC     DX
        MOV     AL,01H                  ;Select ENABLE RESET
        OUT     DX,AL
        INC     DX
        MOV     AL,0FH                  ;Enable all four planes for SET
        OUT     DX,AL
        DEC     DX

        ; Set mask register to preserve unused 7 bits in a byte

        MOV     AL,08H                  ;Select BIT MASK register
        OUT     DX,AL
        MOV     AL,CL                   ;Fetch mask returned earlier
        INC     DX                      ;and set MASK register to it
        OUT     DX,AL
        DEC     DX

        ; Set the pixel to new color

        MOV     AL,ES:[BX]              ;Must latch to preserve old bits
        MOV     ES:[BX],AL              ;Set pixel color to new value

        ; Restore SET/RESET and MASK registers

        MOV     AL,01H                  ;Select ENABLE RESET
        OUT     DX,AL
        INC     DX
        MOV     AL,00H                  ;Disable all four planes for SET
        OUT     DX,AL
        DEC     DX

        MOV     AL,08H                  ;Select BIT MASK register
        OUT     DX,AL
        MOV     AL,0FFH                 ;Enable all 8 bits for write
        INC     DX                      ;(default)
        OUT     DX,AL
        DEC     DX

        ; Restore segment registers and return

        POP     ES
        MOV     SP,BP
        POP     BP
        RET
_Pixel_Set      ENDP

;************************************************************************
; Set pixel at X,Y to color COLOR                                       *
; using the PACKED PIXEL WRITE method                                   *
;************************************************************************

X               EQU     [BP+4]          ;Formal parameters on stack
Y               EQU     [BP+6]
COLOR           EQU     [BP+8]

        PUBLIC  _Pixel_Packed_Write

_Pixel_Packed_Write PROC    NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    ES

        ; Convert x,y address into OFFSET:SEGMENT and get MASK

        MOV     BX,X                    ;Fetch X coordinate
        MOV     AX,Y                    ;Fetch Y coordinate
        CALL    Get_Address             ;Compute SEGMENT:OFFSET address
                                        ;in ES:BX, Mask in CL

        MOV     DX,GRAPHICS_CTL

        ; Select write mode to be 'PACKED PIXEL WRITE'

        MOV     AL,05H                  ;Select MODE register
        OUT     DX,AL
        INC     DX
        MOV     AL,02H                  ;Select write mode to be PACKED WRITE
        OUT     DX,AL
        DEC     DX

        ; Set mask register to preserve unused 7 bits in a byte

        MOV     AL,08H                  ;Select BIT MASK register
        OUT     DX,AL
        MOV     AL,CL                   ;Fetch mask returned earlier
        INC     DX                      ;and set MASK register to it
        OUT     DX,AL
        DEC     DX

        ; Set the pixel to new color

        MOV     AL,COLOR                ;Fetch color passed on the stack
        MOV     AH,ES:[BX]              ;Must read to preserve old bits
        MOV     ES:[BX],AL              ;Set pixel color to new value

        ; Restore MODE and MASK registers

        MOV     AL,05H                  ;Select MODE register
        OUT     DX,AL
        INC     DX
        MOV     AL,00H                  ;Select default write mode
        OUT     DX,AL
        DEC     DX

        MOV     AL,08H                  ;Select BIT MASK register
        OUT     DX,AL
        MOV     AL,0FFH                 ;Enable all 8 bits for write
        INC     DX                      ;(default)
        OUT     DX,AL
        DEC     DX

        ; Restore segment registers and return

        POP     ES
        MOV     SP,BP
        POP     BP
        RET
_Pixel_Packed_Write ENDP


;************************************************************************
; Set pixel at X,Y to color COLOR                                       *
; using the PLANAR PIXEL WRITE method                                   *
;************************************************************************

X               EQU     [BP+4]          ;Formal parameters on stack
Y               EQU     [BP+6]
COLOR           EQU     [BP+8]

        PUBLIC  _Pixel_Write

_Pixel_Write    PROC    NEAR
        PUSH    BP
        MOV     BP,SP
        PUSH    ES

        ; Convert x,y address into OFFSET:SEGMENT and get MASK

        MOV     BX,X                    ;Fetch X coordinate
        MOV     AX,Y                    ;Fetch Y coordinate
        CALL    Get_Address             ;Compute SEGMENT:OFFSET address
                                        ;in ES:BX, Mask in CL

        ; Set mask register to preserve unused 7 bits in a byte

        MOV     DX,GRAPHICS_CTL
        MOV     AL,08H                  ;Select BIT MASK register
        OUT     DX,AL
        MOV     AL,CL                   ;Fetch mask returned earlier
        INC     DX                      ;and set MASK register to it
        OUT     DX,AL
        DEC     DX

        ; Set MAP MASK register to enable all planes and set pixel to 0
        ; then set MAP MASK to enable planes coresponding to color

        MOV     DX,SEQUENCE_CTL
        MOV     AL,02                   ;Select MAP MASK (PLANE SELECT) reg.
        OUT     DX,AL
        INC     DX
        MOV     AL,0FH                  ;Enable all four planes for write
        OUT     DX,AL

        MOV     AH,ES:[BX]              ;Latch data to preserve unused bits
        XOR     AL,AL                   ;Make sure that proper bit is CLEAR
        MOV     ES:[BX],AL              ;Clear all four planes

        MOV     AL,COLOR                ;Fetch color passed on the stack
        AND     AL,0FH                  ;Clear unused bits (use first four)
        OUT     DX,AL                   ;Enable planes as specified in color
        DEC     DX                      ;(MAP MASK reg is still selected)

        ; Set the pixel to new color

        MOV     AL,0FFH                 ;Make sure that proper bit is ON
        MOV     ES:[BX],AL              ;Set pixel color to new value

        ; Restore MASK registers

        MOV     DX,GRAPHICS_CTL
        MOV     AL,08H                  ;Select BIT MASK register
        OUT     DX,AL
        MOV     AL,0FFH                 ;Enable all 8 bits for write
        INC     DX                      ;(default)
        OUT     DX,AL

        MOV     DX,SEQUENCE_CTL
        MOV     AL,02                   ;Select MAP MASK (PLANE SELECT) reg
        OUT     DX,AL
        INC     DX
        MOV     AL,0FH                  ;Enable all four planes for write
        OUT     DX,AL

        ; Restore segment registers and return

        POP     ES
        MOV     SP,BP
        POP     BP
        RET
_Pixel_Write    ENDP

;************************************************************************
; Compute SEGMENT:OFFSET pair from a given x,y address                  *
; of a pixel.  We know that there is HBYTES bytes in each               *
; raster and that each byte  contains eight pixels.                     *
; To find offest of pixel x,y we use the following formula              *
;                                                                       *
;       OFFSET = HBYTES * y + x/8                                       *
;                                                                       *
; To compute which bit within byte is to be changed we get              *
; (x mod 8) which is remainder when x is divided by 8.                  *
; Which is same as keeping last three bits of x.  We use                *
; position within a byte to rotate value 80H so that the                *
; single bit matches the position in a byte.                            *
; Recall that bit7 in a byte represents left most pixel.                *
; Thus MASK is computed as follows:                                     *
;                                                                       *
;       MASK = ROTATE 80H TO THE RIGHT BY (X AND 7)                     *
;                                                                       *
; Entry:        BX - X coordinate (pixel)                               *
;               AX - Y coordinate (raster)                              *
; Exit:         CL - Mask (x mod 8)                                     *
;               BX - Absolute offset in display buffer                  *
;************************************************************************

Get_Address     PROC    NEAR

        ; Compute SEGMENT:OFFSET pair from x,y pair

        MOV     CX,HBYTES               ;Fetch bytes per raster
        MUL     CX                      ;Compute offset past y rasters
        MOV     CL,BL                   ;Keep copy of x for later
        SHR     BX,1                    ;Get offset within raster as x mod 8
        SHR     BX,1
        SHR     BX,1
        ADD     BX,AX                   ;Add offsets together and keep in BX
        MOV     AX,GRAPH_SEG            ;Fetch segment and copy it into ES
        MOV     ES,AX

        ; Compute MASK within byte from x coordinate

        AND     CL,07H                  ;Compute which bit in a byte
        MOV     AL,80H                  ;and use it to rotate mask into positio
        ROR     AL,CL
        MOV     CL,AL                   ;Keep mask in CL

        RET
Get_Address     ENDP
