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

112 lines
8.2 KiB
Markdown

Logical function 0, which writes the CPU data unmodified, is the
standard mode of operation of the ALUs. In this mode, the CPU data is
combined with the latched data by ignoring the latched data entirely.
Expressed as a logical function, this could be considered CPU data ANDed
with 1 (or ORed with 0). This is the mode to use whenever you want to
place CPU data into display memory, replacing the previous contents
entirely. It may occur to you that there is no need to latch display
memory at all when the data unmodified function is selected. In the
sample program, that is true, but if the bit mask is being used, the
latches must be loaded even for the data unmodified function, as I'll
discuss in the next chapter.
Logical functions 1 through 3 cause the CPU data to be ANDed, ORed, and
XORed with the latched data, respectively. Of these, XOR is the most
useful, since exclusive-ORing is a traditional way to perform animation.
The uses of the AND and OR logical functions are less obvious. AND can
be used to mask a blank area into display memory, or to mask off those
portions of a drawing operation that don't overlap an existing display
memory image. OR could conceivably be used to force an image into
display memory over an existing image. To be honest, I haven't
encountered any particularly valuable applications for AND and OR, but
they're the sort of building-block features that could come in handy in
just the right context, so keep them in mind.
### Notes on the ALU/Latch Demo Program {#Heading4}
VGA settings such as the logical function select should be restored to
their default condition before the BIOS is called to output text or draw
pixels. The VGA BIOS does not guarantee that it will set most VGA
registers except on mode sets, and there are so many compatible BIOSes
around that the code of the IBM BIOS is not a reliable guide. For
instance, when the BIOS is called to draw text, it's likely that the
result will be illegible if the Bit Mask register is not in its default
state. Similarly, a mode set should generally be performed before
exiting a program that tinkers with VGA settings.
Along the same lines, the sample program does not explicitly set the Map
Mask register to ensure that all planes are enabled for writing. The
mode set for mode 10H leaves all planes enabled, so I did not bother to
program the Map Mask register, or any other register besides the Data
Rotate register, for that matter. However, the profusion of compatible
BIOSes means there is some small risk in relying on the BIOS to leave
registers set properly. For the highly safety-conscious, the best course
would be to program data control registers such as the Map Mask and Read
Mask explicitly before relying on their contents.
On the other hand, any function the BIOS provides explicitly—as part of
the interface specification—such as setting the palette RAM, should be
used in preference to programming the hardware directly whenever
possible, because the BIOS may mask hardware differences between VGA
implementations.
The code that draws each vertical box in the sample program reads from
display memory immediately before writing to display memory. The read
operation loads the VGA latches. The value that is read is irrelevant as
far as the sample program is concerned. The read operation is present
only because it is necessary to perform a read to load the latches, and
there is no way to read without placing a value in a register. This is a
bit of a nuisance, since it means that the value of some 8-bit register
must be destroyed. Under certain circumstances, a single logical
instruction such as **XOR** or **AND** can be used to perform both the
read to load the latches and then write to modify display memory without
affecting any CPU registers, as we'll see later on.
All text in the sample program is drawn by VGA BIOS function 13H, the
write string function. This function is also present in the AT's BIOS,
but not in the XT's or PC's, and as a result is rarely used; the
function is always available if a VGA is installed, however. Text drawn
with this function is relatively slow. If speed is important, a program
can draw text directly into display memory much faster in any given
display mode. The great virtue of the BIOS write string function in the
case of the VGA is that it provides an uncomplicated way to get text on
the screen reliably in any mode and color, over any background.
The expression used to load DX in the **TEXT\_UP** macro in the sample
program may seem strange, but it's a convenient way to save a byte of
program code and a few cycles of execution time. DX is being loaded with
a word value that's composed of two independent immediate byte values.
The obvious way to implement this would be with
MOV DL,VALUE1
MOV DH,VALUE2
which requires four instruction bytes. By shifting the value destined
for the high byte into the high byte with MASM's shift-left operator,
**SHL** (\*100H would work also), and then logically combining the
values with MASM's **OR** operator (or the **ADD** operator), both
halves of DX can be loaded with a single instruction, as in
MOV DX,(VALUE2 SHL 8) OR VALUE1
which takes only three bytes and is faster, being a single instruction.
(Note, though, that in 32-bit protected mode, there's a size and
performance penalty for 16-bit instructions such as the **MOV** above;
see the first part of this book for details.) As shown, a macro is an
ideal place to use this technique; the macro invocation can refer to two
separate byte values, making matters easier for the programmer, while
the macro itself can combine the values into a single word-sized
constant.
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
![](images/i.jpg) *A minor optimization tip illustrated in the listing is the use of **INC AX** and **DEC AX** in the **DrawVerticalBox** subroutine when only AL actually needs to be modified. Word-sized register increment and decrement instructions (or dword-sized instructions in 32-bit protected mode) are only one byte long, while byte-size register increment and decrement instructions are two bytes long. Consequently, when size counts, it is worth using a whole 16-bit (or 32-bit) register instead of the low 8 bits of that register for **INC** and **DEC**—if you don't need the upper portion of the register for any other purpose, or if you can be sure that the **INC** or **DEC** won't affect the upper part of the register.*
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The latches and ALUs are central to high-performance VGA code, since
they allow programs to process across all four memory planes without a
series of **OUT**s and read/write operations. It is not always easy to
arrange a program to exploit this power, however, because the ALUs are
far more limited than a CPU. In many instances, however, additional
hardware in the VGA, including the bit mask, the set/reset features, and
the barrel shifter, can assist the ALUs in controlling data, as we'll
see in the next few chapters.