abrash-black-book/29-04.md
2013-12-30 20:26:41 +11:00

308 lines
14 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

How does one go about setting the palette registers? Well, it's
certainly possible to set the palette registers directly by addressing
them at registers 0 through 0FH of the Attribute Controller. However,
setting the palette registers is a bit tricky—bit 5 of the Attribute
Controller Index register must be 0 while the palette registers are
written to, and glitches can occur if the updating doesn't take place
during the blanking interval—and besides, it turns out that there's no
need at all to go straight to the hardware on this one. Conveniently,
the EGA BIOS provides us with video function 10H, which supports setting
either any one palette register or all 16 palette registers (and the
overscan register as well) with a single video interrupt.
Video function 10H is invoked by performing an **INT** 10H with AH set
to 10H. If AL is 0 (subfunction 0), then BL contains the number of the
palette register to set, and BH contains the value to set that register
to. If AL is 1 (subfunction 1), then BH contains the value to set the
overscan (border) color to. Finally, if AL is 2 (subfunction 2), then
ES:DX points to a 17-byte array containing the values to set palette
registers 0-15 and the overscan register to. (For completeness, although
it's unrelated to the palette registers, there is one more subfunction
of video function 10H. If AL = 3 (subfunction 3), bit 0 of BL is set to
1 to cause bit 7 of text attributes to select blinking, or set to 0 to
cause bit 7 of text attributes to select highreverse video.)
![](images/29-03.jpg)\
**Figure 29.3**  *Bit organization within a palette register.*
Listing 29.3 uses video function 10H, subfunction 2 to step through all
64 possible colors. This is accomplished by putting up 16 color bars,
one for each of the 16 possible 4-bit pixel values, then changing the
mapping provided by the palette registers to select a different group of
16 colors from the set of 64 each time a key is pressed. Initially,
colors 0-15 are displayed, then 1-16, then 2-17, and so on up to color
3FH wrapping around to colors 0-14, and finally back to colors 0-15. (By
the way, at mode set time the 16 palette registers are not set to colors
0-15, but rather to 0H, 1H, 2H, H, 4H, 5H, 14H, 7H, 38H, 39H, 3AH, 3BH,
3CH, 3DH, 3EH, and 3FH, respectively. Bits 6, 5, and 4—secondary red,
green, and blue—are all set to 1 in palette registers 8-15 in order to
produce high-intensity colors. Palette register 6 is set to 14H to
produce brown, rather than the yellow that the expected value of 6H
would produce.)
When you run Listing 29.3, you'll see that the whole screen changes
color as each new color set is selected. This occurs because most of the
pixels on the screen have a value of 0, selecting the background color
stored in palette register 0, and we're reprogramming palette register 0
right along with the other 15 palette registers.
It's important to understand that in Listing 29.3 the contents of
display memory are never changed after initialization. The only change
is the mapping from the 4-bit pixel data coming out of display memory to
the 6-bit data going to the monitor. For this reason, it's technically
inaccurate to speak of bits in display memory as representing colors;
more accurately, they represent attributes in the range 0-15, which are
mapped to colors 0-3FH by the palette registers.
**LISTING 29.3 L29-3.ASM**
; Program to illustrate the color mapping capabilities of the
; EGA's palette registers.
;
VGA_SEGMENT equ 0a000h
SC_INDEX equ 3c4h ;Sequence Controller Index register
MAP_MASK equ 2 ;Map Mask register index in SC
BAR_HEIGHT equ 14 ;height of each bar
TOP_BAR equ BAR_HEIGHT*6 ;start the bars down a bit to
; leave room for text
;
stack segment para stack STACK'
db 512 dup (?)
stack ends
;
Data segment word DATA'
KeyMsg db Press any key to see the next color set. '
db There are 64 color sets in all.'
db 0dh, 0ah, 0ah, 0ah, 0ah
db 13 dup ( '), Attribute'
db 38 dup ( '), Color$'
;
; Used to label the attributes of the color bars.
;
AttributeNumbers label byte
x= 0
rept 16
if x lt 10
db 0', x+0', h', 0ah, 8, 8, 8
else
db 0', x+A'-10, h', 0ah, 8, 8, 8
endif
x= x+1
endm
db $'
;
; Used to label the colors of the color bars. (Color values are
; filled in on the fly.)
;
ColorNumberslabelbyte
rept 16
db 000h', 0ah, 8, 8, 8, 8
endm
COLOR_ENTRY_LENGTHequ($-ColorNumbers)/16
db $'
;
CurrentColordb?
;
; Space for the array of 16 colors we'll pass to the BIOS, plus
; an overscan setting of black.
;
ColorTable db 16 dup (?), 0
Data ends
;
Code segment
assume cs:Code, ds:Data
Start procnear
cld
mov ax,Data
mov ds,ax
;
; Go to hi-res graphics mode.
;
mov ax,10h ;AH = 0 means mode set, AL = 10h selects
; hi-res graphics mode
int 10h ;BIOS video interrupt
;
; Put up relevant text.
;
mov ah,9 ;DOS print string function
mov dx,offset KeyMsg
int 21h
;
; Put up the color bars, one in each of the 16 possible pixel values
; (which we'll call attributes).
;
mov cx,16 ;we'll put up 16 color bars
sub al,al ;start with attribute 0
BarLoop:
push ax
push cx
call BarUp
pop cx
pop ax
inc ax ;select the next attribute
loop BarLoop
;
; Put up the attribute labels.
;
mov ah,2 ;video interrupt set cursor position function
sub bh,bh ;page 0
mov dh,TOP_BAR/14 ;counting in character rows, match to
; top of first bar, counting in
; scan lines
mov dl,16 ;just to left of bars
int 10h
mov ah,9 ;DOS print string function
mov dx,offset AttributeNumbers
int 21h
;
; Loop through the color set, one new setting per keypress.
;
mov [CurrentColor],0 ;start with color zero
ColorLoop:
;
; Set the palette registers to the current color set, consisting
; of the current color mapped to attribute 0, current color + 1
; mapped to attribute 1, and so on.
;
mov al,[CurrentColor]
mov bx,offset ColorTable
mov cx,16 ;we have 16 colors to set
PaletteSetLoop:
and al,3fh ;limit to 6-bit color values
mov [bx],al ;build the 16-color table used for setting
inc bx ; the palette registers
inc ax
loop PaletteSetLoop
mov ah,10h ;video interrupt palette function
mov al,2 ;subfunction to set all 16 palette registers
; and overscan at once
mov dx,offset ColorTable
push ds
pop es ;ES:DX points to the color table
int 10h ;invoke the video interrupt to set the palette
;
; Put up the color numbers, so we can see how attributes map
; to color values, and so we can see how each color # looks
; (at least on this particular screen).
;
call ColorNumbersUp
;
; Wait for a keypress, so they can see this color set.
;
WaitKey:
mov ah,8 ;DOS input without echo function
int 21h
;
; Advance to the next color set.
;
mov al,[CurrentColor]
inc ax
mov [CurrentColor],al
cmp al,64
jbe ColorLoop
;
; Restore text mode.
;
mov ax,3
int 10h
;
; Done.
;
Done:
mov ah,4ch ;DOS terminate function
int 21h
;
; Puts up a bar consisting of the specified attribute (pixel value),
; at a vertical position corresponding to the attribute.
;
; Input: AL = attribute
;
BarUp proc near
mov dx,SC_INDEX
mov ah,al
mov al,MAP_MASK
out dx,al
inc dx
mov al,ah
out dx,al ;set the Map Mask register to produce
; the desired color
mov ah,BAR_HEIGHT
mul ah ;row of top of bar
add ax,TOP_BAR ;start a few lines down to leave room for
; text
mov dx,80 ;rows are 80 bytes long
mul dx ;offset in bytes of start of scan line bar
; starts on
add ax,20 ;offset in bytes of upper left corner of bar
mov di,ax
mov ax,VGA_SEGMENT
mov es,ax ;ES:DI points to offset of upper left
; corner of bar
mov dx,BAR_HEIGHT
mov al,0ffh
BarLineLoop:
mov cx,40 ;make the bars 40 wide
rep stosb ;do one scan line of the bar
add di,40 ;point to the start of the next scan line
; of the bar
dec dx
jnz BarLineLoop
ret
BarUp endp
;
; Converts AL to a hex digit in the range 0-F.
;
BinToHexDigit proc near
cmp al,9
ja IsHex
add al,0'
ret
IsHex:
add al,A'-10
ret
BinToHexDigit endp
;
; Displays the color values generated by the color bars given the
; current palette register settings off to the right of the color
; bars.
;
ColorNumbersUp proc near
mov ah,2 ;video interrupt set cursor position function
sub bh,bh ;page 0
mov dh,TOP_BAR/14 ;counting in character rows, match to
; top of first bar, counting in
; scan lines
mov dl,20+40+1 ;just to right of bars
int 10h
mov al,[CurrentColor] ;start with the current color
mov bx,offset ColorNumbers+1
;build color number text string on the fly
mov cx,16 ;we've got 16 colors to do
ColorNumberLoop:
pus hax;save the color #
and al,3fh;limit to 6-bit color values
shr al,1
shr al,1
shr al,1
shr al,1 ;isolate the high nibble of the color #
call BinToHexDigit ;convert the high color # nibble
mov [bx],al ; and put it into the text
pop ax ;get back the color #
push ax ;save the color #
and al,0fh ;isolate the low color # nibble
call BinToHexDigit ;convert the low nibble of the
; color # to ASCII
mov [bx+1],al ; and put it into the text
add bx,COLOR_ENTRY_LENGTH ;point to the next entry
pop ax ;get back the color #
inc ax ;next color #
loop ColorNumberLoop
mov ah,9 ;DOS print string function
mov dx,offset ColorNumbers
int 21h ;put up the attribute numbers
ret
ColorNumbersUpendp
;
Start endp
Code ends
end Start