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

126 lines
7.2 KiB
Markdown

#### Setting the DAC {#Heading9}
Like the palette RAM, the DAC registers can be set either directly or
through the BIOS. Again, the BIOS should be used whenever possible, but
there are a few complications here. My experience is that varying
degrees of flicker and screen bounce occur on many VGAs when a large
block of DAC registers is set through the BIOS. That's not a problem
when the DAC is loaded just once and then left that way, as is the case
in Listing 33.1, which we'll get to shortly, but it can be a serious
problem when the color set is changed rapidly ("cycled") to produce
on-screen effects such as rippling colors. My (limited) experience is
that it's necessary to program the DAC directly in order to cycle colors
cleanly, although input from readers who have worked extensively with
VGA color is welcome.
At any rate, the code in this chapter will use the BIOS to set the DAC,
so I'll describe the BIOS DAC-setting functions next. Later, I'll
briefly describe how to set both the palette RAM and DAC registers
directly, and I'll return to the topic in detail in an upcoming chapter
when we discuss color cycling.
An individual DAC register can be set by interrupt 10H, function 10H
(AH=10), subfunction 10H (AL=10H), with BX indicating the register to be
set and the color to which that register is to be set stored in DH
(6-bit red component), CH (6-bit green component), and CL (6-bit blue
component).
A block of sequential DAC registers ranging in size from one register up
to all 256 can be set via subfunction 12H (AL=12H) of interrupt 10H,
function 10H (AH=10H). In this case, BX contains the number of the first
register to set, CX contains the number of registers to set, and ES:DX
contains the address of a table of color entries to which DAC registers
BX through BX+CX-1 are to be set. The color entry for each DAC register
consists of three bytes; the first byte is a 6-bit red component, the
second byte is a 6-bit green component, and the third byte is a 6-bit
blue component, as illustrated by Listing 33.1.
### If You Can't Call the BIOS, Who Ya Gonna Call? {#Heading10}
Although the palette RAM and DAC registers should be set through the
BIOS whenever possible, there are times when the BIOS is not the best
choice or even a choice at all; for example, a protected-mode program
may not have access to the BIOS. Also, as mentioned earlier, it may be
necessary to program the DAC directly when performing color cycling.
Therefore, I'll briefly describe how to set the palette RAM and DAC
registers directly; in Chapter A on the companion CD-ROM I'll discuss
programming the DAC directly in more detail.
The palette RAM registers are Attribute Controller registers 0 through
15. They are set by first reading the Input Status 1 register (at 3DAH
in color mode or 3BAH in monochrome mode) to reset the Attribute
Controller toggle to index mode, then loading the Attribute Controller
Index register (at 3C0H) with the number (0 through 15) of the register
to be loaded. Do *not* set bit 5 of the Index register to 1, as you
normally would, but rather set bit 5 to 0. Setting bit 5 to 0 allows
values to be written to the palette RAM registers, but it also causes
the screen to blank, so you should wait for the start of vertical
retrace before loading palette RAM registers if you don't want the
screen to flicker. (Do you see why it's easier to go through the BIOS?)
Then, write the desired register value to 3C0H, which has now toggled to
become the Attribute Controller Data register. Write any desired number
of additional register number/register data pairs to 3C0H, then write
20H to 3C0H to unblank the screen.
The process of loading the palette RAM registers depends heavily on the
proper sequence being followed; if the Attribute Controller Index
register or index/data toggle data gets changed in the middle of the
loading process, you'll probably end up with a hideous display, or no
display at all. Consequently, for maximum safety you may want to disable
interrupts while you load the palette RAM, to prevent any sort of
interference from a TSR or the like that alters the state of the
Attribute Controller in the middle of the loading sequence.
The DAC registers are set by writing the number of the first register to
set to the DAC Write Index register at 3C8H, then writing three
bytes—the 6-bit red component, the 6-bit green component, and the 6-bit
blue component, in that order—to the DAC Data register at 3C9H. The DAC
Write Index register then autoincrements, so if you write another
three-byte RGB value to the DAC Data register, it'll go to the next DAC
register, and so on indefinitely; you can set all 256 registers by
sending 256\*3 = 768 bytes to the DAC Data Register.
Loading the DAC is just as sequence-dependent and potentially
susceptible to interference as is loading the palette, so my personal
inclination is to go through the whole process of disabling interrupts,
loading the DAC Write Index, and writing a three-byte RGB value
separately for each DAC register; although that doesn't take advantage
of the autoincrementing feature, it seems to me to be least susceptible
to outside influences. (It would be even better to disable interrupts
for the entire duration of DAC register loading, but that's much too
long a time to leave interrupts off.) However, I have no hard evidence
to offer in support of my conservative approach to setting the DAC, just
an uneasy feeling, so I'd be most interested in hearing from any
readers.
A final point is that the process of loading both the palette RAM and
DAC registers involves performing multiple **OUT**s to the same
register. Many people whose opinions I respect recommend delaying
between I/O accesses to the same port by performing a **JMP \$+2**
(jumping flushes the prefetch queue and forces a memory access—or at
least a cache access—to fetch the next instruction byte). In fact, some
people recommend two **JMP \$+2** instructions between I/O accesses to
the same port, and *three* jumps between I/O accesses to the same port
that go in opposite directions (**OUT** followed by **IN** or **IN**
followed by **OUT**). This is clearly necessary when accessing some
motherboard chips, but I don't know how applicable it is when accessing
VGAs, so make of it what you will. Input from knowledgeable readers is
eagerly solicited.
In the meantime, if you can use the BIOS to set the DAC, do so; then you
won't have to worry about the real and potential complications of
setting the DAC directly.
### An Example of Setting the DAC {#Heading11}
This chapter has gotten about as big as a chapter really ought to be;
the VGA color saga will continue in the next few. Quickly, then, Listing
33.1 is a simple example of setting the DAC that gives you a taste of
the spectacular effects that color translation makes possible. There's
nothing particularly complex about Listing 33.1; it just selects
256-color mode, fills the screen with one-pixel-wide concentric diamonds
drawn with sequential attributes, and sets the DAC to produce a smooth
gradient of each of the three primary colors and of a mix of red and
blue. Run the program; I suspect you'll be surprised at the stunning
display this short program produces. Clever color manipulation is
perhaps the easiest way to produce truly eye-catching effects on the PC.