126 lines
7.2 KiB
Markdown
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.
|