130 lines
No EOL
6.8 KiB
Markdown
130 lines
No EOL
6.8 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: '23'
|
|
pages: 427-430
|
|
---
|
|
|
|
### At the Core {#Heading5}
|
|
|
|
A little background is necessary before we're ready to examine Listing
|
|
23.1. The VGA is built around four functional blocks, named the CRT
|
|
Controller (CRTC), the Sequence Controller (SC), the Attribute
|
|
Controller (AC), and the Graphics Controller (GC). The single-chip VGA
|
|
could have been designed to treat the registers for all the blocks as
|
|
one large set, addressed at one pair of I/O ports, but in the EGA, each
|
|
of these blocks was a separate chip, and the legacy of EGA compatibility
|
|
is why each of these blocks has a separate set of registers and is
|
|
addressed at different I/O ports in the VGA.
|
|
|
|
Each of these blocks has a sizable complement of registers. It is not
|
|
particularly important that you understand why a given block has a given
|
|
register; all the registers together make up the programming interface,
|
|
and it is the entire interface that is of interest to the VGA
|
|
programmer. However, the means by which most VGA registers are addressed
|
|
makes it necessary for you to remember which registers are in which
|
|
blocks.
|
|
|
|
Most VGA registers are addressed as *internally indexed* registers. The
|
|
internal address of the register is written to a given block's Index
|
|
register, and then the data for that register is written to the block's
|
|
Data register. For example, GC register 8, the Bit Mask register, is set
|
|
to 0FFH by writing 8 to port 3CEH, the GC Index register, and then
|
|
writing 0FFH to port 3CFH, the GC Data register. Internal indexing makes
|
|
it possible to address the 9 GC registers through only two ports, and
|
|
allows the entire VGA programming interface to be squeezed into fewer
|
|
than a dozen ports. The downside is that two I/O operations are required
|
|
to access most VGA registers.
|
|
|
|
The ports used to control the VGA are shown in Table 23.1. The CRTC, SC,
|
|
and GC Data registers are located at the addresses of their respective
|
|
Index registers plus one. However, the AC Index and Data registers are
|
|
located at the same address, 3C0H. The function of this port toggles on
|
|
every `OUT` to 3C0H, and resets to Index mode (in which the Index
|
|
register is programmed by the next `OUT` to 3C0H) on every read from
|
|
the Input Status 1 register (3DAH when the VGA is in a color mode,
|
|
|
|
| Register | Address |
|
|
|---------------------------------------------|--------------------------|
|
|
| AC Index/Data register | 3C0H (write with toggle) |
|
|
| AC Index register | 3C0H (read) |
|
|
| AC Data register | 3C1H (read) |
|
|
| Miscellaneous Output register | 3C2H (write) |
|
|
| | 3CCH (read) |
|
|
| Input Status 0 register | 3C2H (read) |
|
|
| SC Index register | 3C4H (read/write) |
|
|
| SC Data register | 3C5H (read/write) |
|
|
| GC Index register | 3CEH (read/write) |
|
|
| GC Data register | 3CFH (read/write) |
|
|
| CRTC Index register | 3B4H/3D4H (read/write) |
|
|
| CRTC Data register | 3B5H/3D5H (read/write) |
|
|
| Input Status 1 register/AC Index/Data reset | 3 BAH/3DAH (read) |
|
|
| Feature Control | 3BAH/3DAH (write) |
|
|
| | 3CAH (read) |
|
|
|
|
Table: Table 1.1 The Ports through which the VGA is controlled.
|
|
|
|
3BAH in monochrome modes). Note that all CRTC registers are addressed at
|
|
either 3DXH or 3BXH, the former in color modes and the latter in
|
|
monochrome modes. This provides compatibility with the register
|
|
addressing of the now-vanished Color/Graphics Adapter and Monochrome
|
|
Display Adapter.
|
|
|
|
The method used in the VGA BIOS to set registers is to point DX to the
|
|
desired Index register, load AL with the index, perform a byte `OUT`,
|
|
increment DX to point to the Data register (except in the case of the
|
|
AC, where DX remains the same), load AL with the desired data, and
|
|
perform a byte `OUT`. A handy shortcut is to point DX to the desired
|
|
Index register, load AL with the index, load AH with the data, and
|
|
perform a word `OUT`. Since the high byte of the `OUT` value goes to
|
|
port DX+1, this is equivalent to the first method but is faster.
|
|
However, this technique does not work for programming the AC Index and
|
|
Data registers; both AC registers are addressed at 3C0H, so two separate
|
|
byte `OUT`s must be used to program the AC. (Actually, word `OUT`s
|
|
to the AC do work in the EGA, but not in the VGA, so they shouldn't be
|
|
used.) As mentioned above, you must be sure which mode—Index or Data—the
|
|
AC is in before you do an `OUT` to 3C0H; you can read the Input Status
|
|
1 register at any time to force the AC to Index mode.
|
|
|
|
How safe is the word-`OUT` method of addressing VGA registers? I have,
|
|
in the past, run into adapter/computer combinations that had trouble
|
|
with word `OUT`s; however, all such problems I am aware of have been
|
|
fixed. Moreover, a great deal of graphics software now uses word
|
|
`OUT`s, so any computer or VGA that doesn't properly support word
|
|
`OUT`s could scarcely be considered a clone at all.
|
|
|
|
> 
|
|
> A speed tip: The setting of each chip's Index register remains the same
|
|
> until it is reprogrammed. This means that in cases where you are setting
|
|
> the same internal register repeatedly, you can set the Index register to
|
|
> point to that internal register once, then write to the Data register
|
|
> multiple times. For example, the Bit Mask register (GC register 8) is
|
|
> often set repeatedly inside a loop when drawing lines. The standard code
|
|
> for this is:
|
|
>
|
|
> MOV DX,03CEH ;point to GC Index register
|
|
> MOV AL,8 ;internal index of Bit Mask register
|
|
> OUT DX,AX ;AH contains Bit Mask register setting
|
|
>
|
|
> Alternatively, the GC Index register could initially be set to point to
|
|
> the Bit Mask register with
|
|
>
|
|
> MOV DX,03CEH ;point to GC Index register
|
|
> MOV AL,8 ;internal index of Bit Mask register
|
|
> OUT DX,AL ;set GC Index register
|
|
> INC DX ;point to GC Data register>
|
|
>
|
|
> and then the Bit Mask register could be set repeatedly with the
|
|
> byte-size `OUT` instruction
|
|
>
|
|
> OUT DX,AL ;AL contains Bit Mask register setting
|
|
>
|
|
> which is generally faster (and never slower) than a word-sized `OUT`,
|
|
> and which does not require AH to be set, freeing up a register. Of
|
|
> course, this method only works if the GC Index register remains
|
|
> unchanged throughout the loop. |