94 lines
5.1 KiB
Markdown
94 lines
5.1 KiB
Markdown
---
|
|
title: Michael Abrash's Graphics Programming Black Book, Special Edition
|
|
author: Michael Abrash
|
|
date: '1997-07-01'
|
|
isbn: '1576101746'
|
|
publisher: The Coriolis Group
|
|
category: 'Web and Software Development: Game Development,Web and Software Development:
|
|
Graphics and Multimedia Development'
|
|
chapter: '30'
|
|
pages: 582-584
|
|
---
|
|
|
|
### Notes on Setting and Reading Registers {#Heading10}
|
|
|
|
There are a few interesting points regarding setting and reading
|
|
registers to be made about Listing 30.2. First, bit 5 of the AC Index
|
|
register should be set to 1 whenever palette RAM is not being set (which
|
|
is to say, all the time in your code, because palette RAM should
|
|
normally be set via the BIOS). When bit 5 is 0, video data from display
|
|
memory is no longer sent to palette RAM, and the screen becomes a solid
|
|
color—not normally a desirable state of affairs.
|
|
|
|
Recall also that the AC Index and Data registers are both written to at
|
|
I/O address 3C0H, with the toggle that determines which one is written
|
|
to at any time switching state on every write to 3C0H; this toggle is
|
|
reset to index mode by each read from the Input Status 0 register (3DAH
|
|
in color modes, 3BAH in monochrome modes). The AC Index and Data
|
|
registers can also be written to at 3C1H on the EGA, but not on the VGA,
|
|
so steer clear of that practice.
|
|
|
|
On the VGA, reading AC registers is a bit different from writing to
|
|
them. The AC Data register can be read from 3C0H, and the AC register
|
|
currently addressed by the AC Index register can be read from 3C1H;
|
|
reading does not affect the state of the AC index/data toggle. Listing
|
|
30.2 illustrates reading from and writing to the AC registers. Finally,
|
|
setting the start address registers (CRTC registers 0CH and 0DH) has its
|
|
complications. As with the split screen registers, the start address
|
|
registers must be set together and without interruption at a time when
|
|
there's no chance of a partial setting being used for a frame. However,
|
|
it's a little more difficult to know when that might be the case with
|
|
the start address registers than it was with the split screen registers,
|
|
because it's not clear when the start address is used.
|
|
|
|
You see, the start address is loaded into the EGA's or VGA's internal
|
|
display memory pointer once per frame. The internal pointer is then
|
|
advanced, byte-by-byte and line-by-line, until the end of the frame
|
|
(with a possible resetting to zero if the split screen line is reached),
|
|
and is then reloaded for the next frame. That's straightforward enough;
|
|
the real question is, *Exactly when is the start address loaded?*
|
|
|
|
In his excellent book *Programmer's Guide to PC Video Systems*
|
|
(Microsoft Press) Richard Wilton says that the start address is loaded
|
|
at the start of the vertical sync pulse. (Wilton calls it vertical
|
|
retrace, which can also be taken to mean vertical non-display time, but
|
|
given that he's testing the vertical sync status bit in the Input Status
|
|
0 register, I assume he means that the start address is loaded at the
|
|
start of vertical sync.) Consequently, he waits until the *end* of the
|
|
vertical sync pulse to set the start address registers, confident that
|
|
the start address won't take effect until the next frame.
|
|
|
|
I'm sure Richard is right when it comes to the real McCoy IBM VGA and
|
|
EGA, but I'm less confident that every clone out there loads the start
|
|
address at the start of vertical sync.
|
|
|
|
> 
|
|
> For that very reason, I generally advise people not to use horizontal
|
|
> smooth panning unless they can test their software on all the makes of
|
|
> display adapter it might run on. I've used Richard's approach in
|
|
> Listings 30.1 and 30.2, and so far as I've seen it works fine, but be
|
|
> aware that there are potential, albeit unproven, hazards to relying on
|
|
> the setting of the start address registers to occur at a specific time
|
|
> in the frame.
|
|
|
|
The interaction of the start address registers and the Pel Panning
|
|
register is worthy of note. After waiting for the end of vertical sync
|
|
to set the start address in Listing 30.2, I wait for the start of the
|
|
*next* vertical sync to set the Pel Panning register. That's because the
|
|
start address doesn't take effect until the start of the next frame, but
|
|
the pel panning setting takes effect at the start of the next line; if
|
|
we set the pel panning at the same time we set the start address, we'd
|
|
get a whole frame with the old start address and the new pel panning
|
|
settings mixed together, causing the screen to jump. As with the split
|
|
screen registers, it's safest to set the Pel Panning register during
|
|
non-display time. For maximum reliability, we'd have interrupts off from
|
|
the time we set the start address registers to the time we change the
|
|
pel planning setting, to make sure an interrupt doesn't come in and
|
|
cause us to miss the start of a vertical sync and thus get a mismatched
|
|
pel panning/start address pair for a frame, although for modularity I
|
|
haven't done this in Listing 30.2. (Also, doing so would require
|
|
disabling interrupts for much too long a time.)
|
|
|
|
What if you wanted to pan faster? Well, you could of course just move
|
|
two pixels at a time rather than one; I assure you no one will ever
|
|
notice when you're panning at a rate of 10 or more times per second.
|