3 <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
4 <META NAME="Author" CONTENT="Joshua Neal">
5 <META NAME="Description" CONTENT="Pure VGA/SVGA hardware programming (registers, identification, and otherlow-level stuff.)">
6 <META NAME="KeyWords" CONTENT="VGA SVGA hardware video programming">
7 <TITLE>VGA/SVGA Video Programming--Accessing the VGA Registers</TITLE>
11 <CENTER><A HREF="../home.htm">Home</A> <A HREF="#general">Intro</A> <A HREF="#general">Advice</A>
12 <A HREF="#fudge">Fudge</A> <A HREF="#paranoia">Paranoia</A> <A HREF="#external">External</A>
13 <A HREF="#indexed">Indexed</A> <A HREF="#attribute">Attribute</A> <A HREF="#color">Color</A>
14 <A HREF="#binary">Binary</A> <A HREF="#example">Example</A> <A HREF="#bitfields">Masking</A>
15 <A HREF="vga.htm#register">Back</A>
16 <HR WIDTH="100%"><B>Hardware Level VGA and SVGA Video Programming Information
19 <CENTER>Accessing the VGA Registers
20 <HR WIDTH="100%"></CENTER>
24 <A HREF="#intro">Introduction</A> -- provides a general overview of accessing
25 the VGA registers.</LI>
28 <A HREF="#general">General Advice</A> -- basic guidelines for use when
29 accessing VGA registers.</LI>
32 <A HREF="#fudge">I/O Fudge Factor</A> -- discusses delays between I/O accesses.</LI>
35 <A HREF="#paranoia">Paranoia</A> -- discusses making code more robust.</LI>
38 <A HREF="#external">Accessing the External Registers</A> -- details and
39 guidelines for accessing these registers.</LI>
42 <A HREF="#indexed">Accessing the Sequencer, Graphics, and CRT Controller
43 Registers</A> -- details and guidelines for accessing these registers,
44 including step-by-step instructions.</LI>
47 <A HREF="#attribute">Accessing the Attribute Registers</A> -- details and
48 guidelines for accessing this register, including step-by-step instructions.</LI>
51 <A HREF="#color">Accessing the Color Registers</A> -- details and guidelines
52 for accessing this register, including step-by-step instructions.</LI>
55 <A HREF="#binary">Binary Operations</A> -- details on the operation of
56 the logical operators OR, AND, and XOR.</LI>
59 <A HREF="#example">Example Register</A> -- an example register selected
60 to demonstrate both the format they will be presented in and how fields
64 <A HREF="#bitfields">Masking Bit-Fields</A> -- details on changing specific
65 fields within registers using the logical operators.</LI>
67 <A NAME="intro"></A><B>Introduction</B>
68 <BR> This section discusses methods
69 of manipulating the particular registers present in VGA hardware. Depending
70 upon which register one is accessing, the method of accessing them is different
71 and sometimes difficult to understand. The VGA has many more registers
72 than it has I/O ports, thus it must provide a way to re-use or multiplex
73 many registers onto a relatively small number of ports. All of the VGA
74 ports are accessed by inputting and outputting bytes to I/O ports; however,
75 in many cases it is necessary to perform additional steps to ready the
76 VGA adapter for reading and writing data. Port addresses are given at their
77 hexadecimal address, such as 3C2h.
79 <P><A NAME="general"></A><B>General Advice</B>
80 <BR><B> </B>If a program takes
81 control of the video card and changes its state, it is considered good
82 programming practice to keep track of the original values of any register
83 it changes such that upon termination (normal or abnormal) it can write
84 them back to the hardware to restore the state. Anyone who has seen a graphics
85 application abort in the middle of a graphics screen knows how annoying
86 this can be. Almost all of the VGA registers can be saved and restored
87 in this fashion. In addition when changing only a particular field of a
88 register, the value of the register should be read and the byte should
89 be masked so that only the field one is trying to change is actually changed.
91 <P><A NAME="fudge"></A><B>I/O Fudge Factor</B>
92 <BR> Often a hardware device
93 is not capable handling I/O accesses as fast as the processor can issue
94 them. In this case, a program must provide adequate delay between I/O accesses
95 to the same device. While many modern chipsets provide this delay in hardware,
96 there are still many implementations in existence that do not provide this
97 delay. If you are attempting to write programs for the largest possible
98 variety of hardware configurations, then it is necessary to know the amount
99 of delay necessary. Unfortunately, this delay is not often specified, and
100 varies from one VGA implementation to another. In the interest of performance
101 it is ideal to keep this delay to the minimum necessary. In the interest
102 of compatibility it is necessary to implement a delay independent of clock
103 speed. (Faster processors are continuously being developed, and also a
104 user may change clock speed dynamically via the Turbo button on their case.)
106 <P><A NAME="paranoia"></A><B>Paranoia</B>
107 <BR> If one wishes to be extra
108 cautious when writing to registers, after writing to a register one can
109 read the value back and compare it with the original value. If they differ
110 it may mean that the VGA hardware has a stuck bit in one its registers,
111 that you are attempting to modify a locked or unsupported register, or
112 that you are not providing enough delay between I/O accesses. As long as
113 reading the register twice doesn't have any unintended side effects, when
114 reading a registers value, one can read the register twice and compare
115 the values read, after masking out any fields that may change without CPU
116 intervention. If the values read back are different it may mean that you
117 are not providing enough delay between I/O accesses, that the hardware
118 is malfunctioning, or are reading the wrong register or field. Other problems
119 that these techniques can address are noise on the I/O bus due to faulty
120 hardware, dirty contacts, or even sunspots! When perform I/O operations
121 and these checks fail, try repeating the operation, possibly with increased
122 I/O delay time. By providing extra robustness, I have found that my own
123 programs will work properly on hardware that causes less robust programs
126 <P><A NAME="external"></A><B>Accessing the External Registers</B>
127 <BR> The external registers are
128 the easiest to program, because they each have their own separate I/O address.
129 Reading and writing to them is as simple as inputting and outputting bytes
130 to their respective port address. Note, however some, such as the Miscellaneous
131 Output Register is written at port 3C2h, but is read at port 3CCh. The
132 reason for this is for backwards compatibility with the EGA and previous
133 adapters. Many registers in the EGA were write only, and thus the designers
134 placed read-only registers at the same location as write-only ones. However,
135 the biggest complaint programmers had with the EGA was the inability to
136 read the EGA's video state and thus in the design of the VGA most of these
137 write-only registers were changed to read/write registers. However, for
138 backwards compatibility, the read-only register had to remain at 3C2h,
139 so they used a different port.
141 <P><A NAME="indexed"></A><B>Accessing the Sequencer, Graphics, and CRT
142 Controller Registers</B>
143 <BR> These registers are accessed
144 in an indexed fashion. Each of the three have two unique read/write ports
145 assigned to them. The first port is the Address Register for the group.
146 The other is the Data Register for the group. By writing a byte to the
147 Address Register equal to the index of the particular sub-register you
148 wish to access, one can address the data pointed to by that index by reading
149 and writing the Data Register. The current value of the index can be read
150 by reading the Address Register. It is best to save this value and restore
151 it after writing data, particularly so in an interrupt routine because
152 the interrupted process may be in the middle of writing to the same register
153 when the interrupt occurred. To read and write a data register in one of
154 these register groups perform the following procedure:
157 Input the value of the Address Register and save it for step 6</LI>
160 Output the index of the desired Data Register to the Address Register.</LI>
163 Read the value of the Data Register and save it for later restoration upon
164 termination, if needed.</LI>
167 If writing, modify the value read in step 3, making sure to mask off bits
168 not being modified.</LI>
171 If writing, write the new value from step 4 to the Data register.</LI>
174 Write the value of Address register saved in step 1 to the Address Register.</LI>
176 If you are paranoid, then you
177 might want to read back and compare the bytes written in step 2, 5, and
178 6 as in the <A HREF="#paranoia">Paranoia</A> section above. Note that certain
179 CRTC registers can be protected from read or write access for compatibility
180 with programs written prior to the VGA's existence. This protection is
181 controlled via the <A HREF="crtcreg.htm#03">Enable Vertical Retrace Access</A>
182 and <A HREF="crtcreg.htm#11">CRTC Registers Protect Enable</A> fields.
183 Ensuring that access is not prevented even if your card does not normally
184 protect these registers makes your
186 <P><A NAME="attribute"></A><B>Accessing the Attribute Registers</B>
187 <BR> The attribute registers
188 are also accessed in an indexed fashion, albeit in a more confusing way.
189 The address register is read and written via port 3C0h. The data register
190 is written to port 3C0h and read from port 3C1h. The index and the data
191 are written to the same port, one after another. A flip-flop inside the
192 card keeps track of whether the next write will be handled is an index
193 or data. Because there is no standard method of determining the state of
194 this flip-flop, the ability to reset the flip-flop such that the next write
195 will be handled as an index is provided. This is accomplished by reading
196 the Input Status #1 Register (normally port 3DAh) (the data received is
197 not important.) This can cause problems with interrupts because there is
198 no standard way to find out what the state of the flip-flop is; therefore
199 interrupt routines require special card when reading this register. (Especially
200 since the Input Status #1 Register's purpose is to determine whether a
201 horizontal or vertical retrace is in progress, something likely to be read
202 by an interrupt routine that deals with the display.) If an interrupt were
203 to read 3DAh in the middle of writing to an address/data pair, then the
204 flip-flop would be reset and the data would be written to the address register
205 instead. Any further writes would also be handled incorrectly and thus
206 major corruption of the registers could occur. To read and write an data
207 register in the attribute register group, perform the following procedure:
210 Input a value from the Input Status #1 Register (normally port 3DAh) and
214 Read the value of the Address/Data Register and save it for step 7.</LI>
217 Output the index of the desired Data Register to the Address/Data Register</LI>
220 Read the value of the Data Register and save it for later restoration upon
221 termination, if needed.</LI>
224 If writing, modify the value read in step 4, making sure to mask off bits
225 not being modified.</LI>
228 If writing, write the new value from step 5 to the Address/Data register.</LI>
231 Write the value of Address register saved in step 1 to the Address/Data
235 If you wish to leave the register waiting for an index, input a value from
236 the Input Status #1 Register (normally port 3DAh) and discard it.</LI>
238 If you have control over interrupts,
239 then you can disable interrupts while in the middle of writing to the register.
240 If not, then you may be able to implement a critical section where you
241 use a byte in memory as a flag whether it is safe to modify the attribute
242 registers and have your interrupt routine honor this. And again, it pays
243 to be paranoid. Resetting the flip-flop even though it <B>should</B> be
244 in the reset state already helps prevent catastrophic problems. Also, you
245 might want to read back and compare the bytes written in step 3, 6, and
246 7 as in the <A HREF="#paranoia">Paranoia</A> section above.
247 <BR> On the IBM VGA implementation,
248 an undocumented register (CRTC Index=24h, bit 7) can be read to determine
249 the status of the flip-flop (0=address,1=data) and many VGA compatible
250 chipsets duplicate this behavior, but it is not guaranteed. However, it
251 is a simple matter to determine if this is the case. Also, some SVGA chipsets
252 provide the ability to access the attribute registers in the same fashion
253 as the CRT, Sequencer, and Graphics controllers. Because this functionality
254 is vendor specific it is really only useful when programming for that particular
255 chipset. To determine if this undocumented bit is supported, perform the
259 Input a value from the Input Status #1 Register (normally port 3DAh) and
263 Verify that the flip-flop status bit (CRTC Index 24, bit 7) is 0. If bit=1
264 then feature is not supported, else continue to step 3.</LI>
267 Output an address value to the Attribute Address/Data register.</LI>
270 Verify that the flip-flop status bit (CRTC Index 24, bit 7) is 1. If bit=0
271 then feature is not supported, else continue to step 5.</LI>
274 Input a value from the Input Status #1 Register (normally port 3DAh) and
278 Verify that the flip-flop status bit (CRTC Index 24, bit 7) is 0. If bit=1
279 then feature is not supported, else feature is supported.</LI>
281 <A NAME="color"></A><B>Accessing the Color Registers</B>
282 <BR> The color registers require an altogether
283 different technique; this is because the 256-color palette requires 3 bytes
284 to store 18-bit color values. In addition the hardware supports the capability
285 to load all or portions of the palette rapidly. To write to the palette,
286 first you must output the value of the palette entry to the PEL Address
287 Write Mode Register (port 3C8h.) Then you should output the component values
288 to the PEL Data Register (port 3C9h), in the order red, green, then blue.
289 The PEL Address Write Mode Register will then automatically increment,
290 allowing the component values of the palette entry to be written to the
291 PEL Data Register. Reading is performed similarly, except that the PEL
292 Address Read Mode Register (port 3C7h) is used to specify the palette entry
293 to be read, and the values are read from the PEL Data Register. Again,
294 the PEL Address Read Mode Register auto-increments after each triplet is
295 written. The current index for the current operation can be read from the
296 PEL Address Write Mode Register. Reading port 3C7h gives the DAC State
297 Register, which specifies whether a read operation or a write operation
298 is in effect. As in the attribute registers, there is guaranteed way for
299 an interrupt routine to access the color registers and return the color
300 registers to the state they were in prior to access without some communication
301 between the ISR and the main program. For some workarounds see the <A HREF="#attribute">Accessing
302 the Attribute Registers</A> section above. To read the color registers:
305 Read the DAC State Register and save the value for use in step 8.</LI>
308 Read the PEL Address Write Mode Register for use in step 8.</LI>
311 Output the value of the first color entry to be read to the PEL Address
312 Read Mode Register.</LI>
315 Read the PEL Data Register to obtain the red component value.</LI>
318 Read the PEL Data Register to obtain the green component value.</LI>
321 Read the PEL Data Register to obtain the blue component value.</LI>
324 If more colors are to be read, repeat steps 4-6.</LI>
327 Based upon the DAC State from step 1, write the value saved in step 2 to
328 either the PEL Address Write Mode Register or the PEL Address Read Mode
331 Note: Steps 1, 2, and 8 are hopelessly optimistic. This in no way guarantees
332 that the state is preserved, and with some DAC implementations this may
333 actually guarantee that the state is never preserved. See the <A HREF="vgadac.htm">DAC
334 Operation</A> page for more details.
336 <P><A NAME="binary"></A><B>Binary Operations</B>
337 <BR><B> </B>In order to better
338 understand dealing with bit fields it is necessary to know a little bit
339 about logical operations such as logical-and (AND), logical-or (OR), and
340 exclusive-or(XOR.) These operations are performed on a bit by bit basis
341 using the truth tables below. All of these operations are commutative,
342 i.e. A OR B = B OR A, so you look up one bit in the left column and the
343 other in the top row and consult the intersecting row and column for the
346 <CENTER><TABLE BORDER WIDTH="500" >
348 <TD COLSPAN="3"><B>AND</B></TD>
352 <TD COLSPAN="3"><B>OR</B></TD>
356 <TD COLSPAN="3"><B>XOR</B></TD>
360 <TD WIDTH="10%"></TD>
362 <TD WIDTH="10%"><B>0</B></TD>
364 <TD WIDTH="10%"><B>1</B></TD>
368 <TD WIDTH="10%"></TD>
370 <TD WIDTH="10%"><B>0</B></TD>
372 <TD WIDTH="10%"><B>1</B></TD>
376 <TD WIDTH="10%"></TD>
378 <TD WIDTH="10%"><B>0</B></TD>
380 <TD WIDTH="10%"><B>1</B></TD>
432 <A NAME="example"></A><B>Example Register</B>
433 <BR> The following table is an
434 example of one particular register, the Mode Register of the Graphics Register.
435 Each number from 7-0 represents the bit position in the byte. Many registers
436 contain more than one field, each of which performs a different function.
437 This particular chart contains four fields, two of which are two bits in
438 length. It also contains two bits which are not implemented (to the best
439 of my knowledge) by the standard VGA hardware.
441 <TABLE BORDER WIDTH="600" CELLPADING="2" >
442 <CAPTION ALIGN=TOP><B>Mode Register (Index 05h)</B></CAPTION>
444 <TR ALIGN=CENTER VALIGN=CENTER>
445 <TD WIDTH="75">7</TD>
447 <TD WIDTH="75">6</TD>
449 <TD WIDTH="75">5</TD>
451 <TD WIDTH="75">4</TD>
453 <TD WIDTH="75">3</TD>
455 <TD WIDTH="75">2</TD>
457 <TD WIDTH="75">1</TD>
459 <TD WIDTH="75">0</TD>
462 <TR ALIGN=CENTER VALIGN=CENTER>
465 <TD COLSPAN="2" WIDTH="150">Shift Register</TD>
467 <TD WIDTH="75">Odd/Even</TD>
469 <TD WIDTH="75">RM</TD>
473 <TD COLSPAN="2" WIDTH="150">Write Mode</TD>
477 <A NAME="bitfields"></A><B>Masking Bit-Fields</B>
478 <BR> Your development environment
479 may provide some assistance in dealing with bit fields. Consult your documentation
480 for this. In addition it can be performed using the logical operators AND,
481 OR, and XOR (for details on these operators see the <A HREF="#binary">Binary
482 Operations</A> section above.) To change the value of the Shift Register
483 field of the example register above, we would first mask out the bits we
484 do not wish to change. This is accomplished by performing a logical AND
485 of the value read from the register and a binary value in which all of
486 the bits we wish to leave alone are set to 1, which would be 10011111b
487 for our example. This leaves all of the bits except the Shift Register
488 field alone and set the Shift Register field to zero. If this was our goal,
489 then we would stop here and write the value back to the register. We then
490 OR the value with a binary number in which the bits are shifted into position.
491 To set this field to 10b we would OR the result of the AND with 01000000b.
492 The resulting byte would then be written to the register. To set a bitfield
493 to all ones the AND step is not necessary, similar to setting the bitfield
494 to all zeros using AND. To toggle a bitfield you can XOR a value with a
495 byte with a ones in the positions to toggle. For example XORing the value
496 read with 01100000b would toggle the value of the Shift Register bitfield.
497 By using these techniques you can assure that you do not cause any unwanted
498 "side-effects" when modifying registers.
500 <P>Notice: All trademarks used or referred to on this page are the property
501 of their respective owners.
502 <BR>All pages are Copyright © 1997, 1998, J. D. Neal, except where
503 noted. Permission for utilization and distribution is subject to the terms
504 of the <A HREF="license.htm">FreeVGA Project Copyright License</A>.