112 lines
8.2 KiB
Markdown
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.
|
|
|
|
------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
 *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.
|