Previous Table of Contents Next


LISTING 28.2 L28-2.ASM

; Program to illustrate use of read mode 1 (color compare mode)
; to detect collisions in display memory. Draws a yellow line on a
; blue background, then draws a perpendicular green line until the
; yellow line is reached.
;
; By Michael Abrash
;
stack segment     word stack `STACK'
      db    512 dup (?)
stack ends
;
VGA_SEGMENT       EQU    0a000h
SCREEN_WIDTH             EQU   80    ;in bytes
GC_INDEX          EQU    3ceh        ;Graphics Controller Index register
SET_RESET         EQU    0           ;Set/Reset register index in GC
ENABLE_SET_RESET  EQU    1           ;Enable Set/Reset register index in GC
COLOR_COMPARE     EQU    2           ;Color Compare register index in GC
GRAPHICS_MODE     EQU    5           ;Graphics Mode register index in GC
BIT_MASK          EQU    8           ;Bit Mask register index in GC
;
code              segment   word `CODE'
                  assume    cs:code
Start             proc      near
                  cld
;
; Select graphics mode 10h.
;
     mov    ax,10h
     int    10h
;
; Fill the screen with blue.
;
     mov    al,1                  ;blue is color 1
     call   SelectSetResetColor   ;set to draw in blue
     mov    ax,VGA_SEGMENT
     move   s,ax
     sub    di,di
     mov    cx,7000h
     rep    stosb                 ;the value written actually doesn't
; matter, since set/reset is providing
; the data written to display memory
;
; Draw a vertical yellow line.
;
     mov    al,14                 ;yellow is color 14
     call   SelectSetResetColor   ;set to draw in yellow
     mov    dx,GC_INDEX
     mov    al,BIT_MASK
     out    dx,al                 ;point GC Index to Bit Mask
     inc    dx                    ;point to GC Data
     mov    al,10h
     out    dx,al                 ;set Bit Mask to 10h
     mov    di,40                 ;start in the middle of the top line
     mov    cx,350                ;do full height of screen
VLineLoop:
     mov    al,es:[di]            ;load the latches
     stosb                        ;write next pixel of yellow line (set/reset
; provides the data written to display
; memory, and AL is actually ignored)
     add    di,SCREEN_WIDTH-1     ;point to the next scan line
loopVLineLoop
;
; Select write mode 0 and read mode 1.
;
     mov    dx,GC_INDEX
     mov    al,GRAPHICS_MODE
     out    dx,al                 ;point GC Index to Graphics Mode register
     inc    dx                    ;point to GC Data
     mov    al,00001000b          ;bit 3=1 is read mode 1, bits 1 & 0=00
                                  ; is write mode 0
     out    dx,al                 ;set Graphics Mode to read mode 1,
                                  ; write mode 0
;
; Draw a horizontal green line, one pixel at a time, from left
; to right until color compare reports a yellow pixel is encountered.
;
; Draw in green.
;
     mov    al,2                  ;green is color 2
     call    SelectSetResetColor  ;set to draw in green
;
; Set color compare to look for yellow.
;
     mov    dx,GC_INDEX
     mov    al,COLOR_COMPARE
     out    dx,al                 ;point GC Index to Color Compare register
     inc    dx                    ;point to GC Data
     mov    al,14                 ;we're looking for yellow, color 14
     out    dx,al                 ;set color compare to look for yellow
     dec    dx                    ;point to GC Index
;
; Set up for quick access to Bit Mask register.
;
     mov    al,BIT_MASK
     out    dx,al                 ;point GC Index to Bit Mask register
     inc    dx                    ;point to GC Data
;
; Set initial pixel mask and display memory offset.
;
     mov    al,80h                ;initial pixel mask
     mov    di,100*SCREEN_WIDTH
                                  ;start at left edge of scan line 100
HLineLoop:
     mov    ah,es:[di]            ;do a read mode 1 (color compare) read.
                                  ; This also loads the latches.
     and    ah,al                 ;is the pixel of current interest yellow?
     jnz    WaitKeyAndDone        ;yes-we've reached the yellow line, so we're
                                  ; done
     out    dx,al                 ;set the Bit Mask register so that we
                                  ; modify only the pixel of interest
     mov    es:[di],al            ;draw the pixel. The value written is
                                  ; irrelevant, since set/reset is providing
                                  ; the data written to display memory
     ror    al,1                  ;shift pixel mask to the next pixel
     adc    di,0                  ;advance the display memory offset if
                                  ; the pixel mask wrapped
;
; Slow things down a bit for visibility (adjust as needed).
;
     mov    cx,0
DelayLoop:
     loop   DelayLoop
     jmp    HLineLoop
;
; Wait for a key to be pressed to end, then return to text mode and
; return to DOS.
;
WaitKeyAndDone:
WaitKeyLoop:
     mov    ah,1
     int    16h
     jz    WaitKeyLoop
     sub    ah,ah
     int    16h                   ;clear the key
     mov    ax,3
     int    10h                   ;return to text mode
     mov    ah,4ch
     int    21h                   ;done
Startendp
;
; Enables set/reset for all planes, and sets the set/reset color
; to AL.
;
SelectSetResetColorprocnear
     mov    dx,GC_INDEX
     push   ax                    ;preserve color
     mov    al,SET_RESET
     out    dx,al                 ;point GC Index to Set/Reset register
     inc    dx                    ;point to GC Data
     pop    ax                    ;get back color
     out    dx,al                 ;set Set/Reset register to selected color
     dec    dx                    ;point to GC Index
     mov    al,ENABLE_SET_RESET
     out    dx,al                 ;point GC Index to Enable Set/Reset register
     inc    dx                    ;point to GC Data
     mov    al,0fh
     out    dx,al                 ;enable set/reset for all planes
     ret
SelectSetResetColorendp
code ends
end  Start

When all Planes “Don’t Care”

Still and all, there aren’t all that many uses for basic color compare operations. There is, however, a genuinely odd application of read mode 1 that’s worth knowing about; but in order to understand that, we must first look at the “don’t care” aspect of color compare operation.

As described earlier, during read mode 1 reads the color stored in the Color Compare register is compared to each of the 8 pixels at a given address in VGA memory. But—and it’s a big but—any plane for which the corresponding bit in the Color Don’t Care register is a 0 is always considered a color compare match, regardless of the values of that plane’s bits in the pixels and in the Color Compare register.

Let’s look at this another way. A given pixel is controlled by four bits, one in each plane. Normally (when the Color Don’t Care register is 0FH), the color in the Color Compare register is compared to the four bits of each pixel; bit 0 of the Color Compare register is compared to the plane 0 bit of each pixel, bit 1 of the Color Compare register is compared to the plane 1 bit of each pixel, and so on. That is, when the lower four bits of the Color Don’t Care register are all set to 1, then all four bits of a given pixel must match the Color Compare register in order for a read mode 1 read to return a 1 for that pixel to the CPU.

However, if any bit of the Color Don’t Care register is 0, then the corresponding bit of each pixel is unconditionally considered to match the corresponding bit of the Color Compare register. You might think of the Color Don’t Care register as selecting exactly which planes should matter in a given read mode 1 read. At the extreme, if all bits of the Color Don’t Care register are 0, then read mode 1 reads will always return 0FFH, since all planes are considered to match all bits of all pixels.

Now, we’re all prone to using tools the “right” way—that is, in the way in which they were intended to be used. By that token, the Color Don’t Care register is clearly intended to mask one or more planes out of a color comparison, and as such, has limited use. However, the Color Don’t Care register becomes far more interesting in exactly the “extreme” case described above, where all planes become “don’t care” planes.

Why? Well, as I’ve said, when all planes are “don’t care” planes, read mode 1 reads always return 0FFH. Now, when you AND any value with 0FFH, the value remains unchanged, and that can be awfully handy when you’re using the bit mask to modify selected pixels in VGA memory. Recall that you must always read VGA memory to load the latches before writing to VGA memory when you’re using the bit mask. Traditionally, two separate instructions—a read followed by a write—are used to perform this task. The code in Listing 28.2 uses this approach. Suppose, however, that you’ve set the VGA to read mode 1, with the Color Don’t Care register set to 0 (meaning all reads of VGA memory will return 0FFH). Under these circumstances, you can use a single AND instruction to both read and write VGA memory, since ANDing any value with 0FFH leaves that value unchanged.


Previous Table of Contents Next

Graphics Programming Black Book © 2001 Michael Abrash