Specifications.
[pintos-anon] / specs / freevga / vga / vgareg.htm
diff --git a/specs/freevga/vga/vgareg.htm b/specs/freevga/vga/vgareg.htm
new file mode 100644 (file)
index 0000000..45d3162
--- /dev/null
@@ -0,0 +1,508 @@
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="Author" CONTENT="Joshua Neal">
+   <META NAME="Description" CONTENT="Pure VGA/SVGA hardware programming (registers, identification, and otherlow-level stuff.)">
+   <META NAME="KeyWords" CONTENT="VGA SVGA hardware video programming">
+   <TITLE>VGA/SVGA Video Programming--Accessing the VGA Registers</TITLE>
+</HEAD>
+<BODY>
+
+<CENTER><A HREF="../home.htm">Home</A> <A HREF="#general">Intro</A> <A HREF="#general">Advice</A>
+<A HREF="#fudge">Fudge</A> <A HREF="#paranoia">Paranoia</A> <A HREF="#external">External</A>
+<A HREF="#indexed">Indexed</A> <A HREF="#attribute">Attribute</A> <A HREF="#color">Color</A>
+<A HREF="#binary">Binary</A> <A HREF="#example">Example</A> <A HREF="#bitfields">Masking</A>
+<A HREF="vga.htm#register">Back</A>&nbsp;
+<HR WIDTH="100%"><B>Hardware Level VGA and SVGA Video Programming Information
+Page</B></CENTER>
+
+<CENTER>Accessing the VGA Registers&nbsp;
+<HR WIDTH="100%"></CENTER>
+
+<UL>
+<LI>
+<A HREF="#intro">Introduction</A> -- provides a general overview of accessing
+the VGA registers.</LI>
+
+<LI>
+<A HREF="#general">General Advice</A> -- basic guidelines for use when
+accessing VGA registers.</LI>
+
+<LI>
+<A HREF="#fudge">I/O Fudge Factor</A> -- discusses delays between I/O accesses.</LI>
+
+<LI>
+<A HREF="#paranoia">Paranoia</A> -- discusses making code more robust.</LI>
+
+<LI>
+<A HREF="#external">Accessing the External Registers</A> -- details and
+guidelines for accessing these registers.</LI>
+
+<LI>
+<A HREF="#indexed">Accessing the Sequencer, Graphics, and CRT Controller
+Registers</A> -- details and guidelines for accessing these registers,
+including step-by-step instructions.</LI>
+
+<LI>
+<A HREF="#attribute">Accessing the Attribute Registers</A> -- details and
+guidelines for accessing this register, including step-by-step instructions.</LI>
+
+<LI>
+<A HREF="#color">Accessing the Color Registers</A> -- details and guidelines
+for accessing this register, including step-by-step instructions.</LI>
+
+<LI>
+<A HREF="#binary">Binary Operations</A> -- details on the operation of
+the logical operators OR, AND, and XOR.</LI>
+
+<LI>
+<A HREF="#example">Example Register</A> -- an example register selected
+to demonstrate both the format they will be presented in and how fields
+work.</LI>
+
+<LI>
+<A HREF="#bitfields">Masking Bit-Fields</A> -- details on changing specific
+fields within registers using the logical operators.</LI>
+</UL>
+<A NAME="intro"></A><B>Introduction</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This section discusses methods
+of manipulating the particular registers present in VGA hardware. Depending
+upon which register one is accessing, the method of accessing them is different
+and sometimes difficult to understand. The VGA has many more registers
+than it has I/O ports, thus it must provide a way to re-use or multiplex
+many registers onto a relatively small number of ports. All of the VGA
+ports are accessed by inputting and outputting bytes to I/O ports; however,
+in many cases it is necessary to perform additional steps to ready the
+VGA adapter for reading and writing data. Port addresses are given at their
+hexadecimal address, such as 3C2h.
+
+<P><A NAME="general"></A><B>General Advice</B>
+<BR><B>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </B>If a program takes
+control of the video card and changes its state, it is considered good
+programming practice to keep track of the original values of any register
+it changes such that upon termination (normal or abnormal) it can write
+them back to the hardware to restore the state. Anyone who has seen a graphics
+application abort in the middle of a graphics screen knows how annoying
+this can be. Almost all of the VGA registers can be saved and restored
+in this fashion. In addition when changing only a particular field of a
+register, the value of the register should be read and the byte should
+be masked so that only the field one is trying to change is actually changed.
+
+<P><A NAME="fudge"></A><B>I/O Fudge Factor</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Often a hardware device
+is not capable handling I/O accesses as fast as the processor can issue
+them. In this case, a program must provide adequate delay between I/O accesses
+to the same device. While many modern chipsets provide this delay in hardware,
+there are still many implementations in existence that do not provide this
+delay. If you are attempting to write programs for the largest possible
+variety of hardware configurations, then it is necessary to know the amount
+of delay necessary. Unfortunately, this delay is not often specified, and
+varies from one VGA implementation to another. In the interest of performance
+it is ideal to keep this delay to the minimum necessary. In the interest
+of compatibility it is necessary to implement a delay independent of clock
+speed. (Faster processors are continuously being developed, and also a
+user may change clock speed dynamically via the Turbo button on their case.)
+
+<P><A NAME="paranoia"></A><B>Paranoia</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If one wishes to be extra
+cautious when writing to registers, after writing to a register one can
+read the value back and compare it with the original value. If they differ
+it may mean that the VGA hardware has a stuck bit in one its registers,
+that you are attempting to modify a locked or unsupported register, or
+that you are not providing enough delay between I/O accesses. As long as
+reading the register twice doesn't have any unintended side effects, when
+reading a registers value, one can read the register twice and compare
+the values read, after masking out any fields that may change without CPU
+intervention. If the values read back are different it may mean that you
+are not providing enough delay between I/O accesses, that the hardware
+is malfunctioning, or are reading the wrong register or field. Other problems
+that these techniques can address are noise on the I/O bus due to faulty
+hardware, dirty contacts, or even sunspots! When perform I/O operations
+and these checks fail, try repeating the operation, possibly with increased
+I/O delay time. By providing extra robustness, I have found that my own
+programs will work properly on hardware that causes less robust programs
+to fail.
+
+<P><A NAME="external"></A><B>Accessing the External Registers</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The external registers are
+the easiest to program, because they each have their own separate I/O address.
+Reading and writing to them is as simple as inputting and outputting bytes
+to their respective port address. Note, however some, such as the Miscellaneous
+Output Register is written at port 3C2h, but is read at port 3CCh. The
+reason for this is for backwards compatibility with the EGA and previous
+adapters. Many registers in the EGA were write only, and thus the designers
+placed read-only registers at the same location as write-only ones. However,
+the biggest complaint programmers had with the EGA was the inability to
+read the EGA's video state and thus in the design of the VGA most of these
+write-only registers were changed to read/write registers. However, for
+backwards compatibility, the read-only register had to remain at 3C2h,
+so they used a different port.
+
+<P><A NAME="indexed"></A><B>Accessing the Sequencer, Graphics, and CRT
+Controller Registers</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; These registers are accessed
+in an indexed fashion. Each of the three have two unique read/write ports
+assigned to them. The first port is the Address Register for the group.
+The other is the Data Register for the group. By writing a byte to the
+Address Register equal to the index of the particular sub-register you
+wish to access, one can address the data pointed to by that index by reading
+and writing the Data Register. The current value of the index can be read
+by reading the Address Register. It is best to save this value and restore
+it after writing data, particularly so in an interrupt routine because
+the interrupted process may be in the middle of writing to the same register
+when the interrupt occurred. To read and write a data register in one of
+these register groups perform the following procedure:
+<OL>
+<LI>
+Input the value of the Address Register and save it for step 6</LI>
+
+<LI>
+Output the index of the desired Data Register to the Address Register.</LI>
+
+<LI>
+Read the value of the Data Register and save it for later restoration upon
+termination, if needed.</LI>
+
+<LI>
+If writing, modify the value read in step 3, making sure to mask off bits
+not being modified.</LI>
+
+<LI>
+If writing, write the new value from step 4 to the Data register.</LI>
+
+<LI>
+Write the value of Address register saved in step 1 to the Address Register.</LI>
+</OL>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If you are paranoid, then you
+might want to read back and compare the bytes written in step 2, 5, and
+6 as in the <A HREF="#paranoia">Paranoia</A> section above. Note that certain
+CRTC registers can be protected from read or write access for compatibility
+with programs written prior to the VGA's existence. This protection is
+controlled via the <A HREF="crtcreg.htm#03">Enable Vertical Retrace Access</A>
+and <A HREF="crtcreg.htm#11">CRTC Registers Protect Enable</A> fields.
+Ensuring that access is not prevented even if your card does not normally
+protect these registers makes your
+
+<P><A NAME="attribute"></A><B>Accessing the Attribute Registers</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The attribute registers
+are also accessed in an indexed fashion, albeit in a more confusing way.
+The address register is read and written via port 3C0h. The data register
+is written to port 3C0h and read from port 3C1h. The index and the data
+are written to the same port, one after another. A flip-flop inside the
+card keeps track of whether the next write will be handled is an index
+or data. Because there is no standard method of determining the state of
+this flip-flop, the ability to reset the flip-flop such that the next write
+will be handled as an index is provided. This is accomplished by reading
+the Input Status #1 Register (normally port 3DAh) (the data received is
+not important.) This can cause problems with interrupts because there is
+no standard way to find out what the state of the flip-flop is; therefore
+interrupt routines require special card when reading this register. (Especially
+since the Input Status #1 Register's purpose is to determine whether a
+horizontal or vertical retrace is in progress, something likely to be read
+by an interrupt routine that deals with the display.) If an interrupt were
+to read 3DAh in the middle of writing to an address/data pair, then the
+flip-flop would be reset and the data would be written to the address register
+instead. Any further writes would also be handled incorrectly and thus
+major corruption of the registers could occur. To read and write an data
+register in the attribute register group, perform the following procedure:
+<OL>
+<LI>
+Input a value from the Input Status #1 Register (normally port 3DAh) and
+discard it.</LI>
+
+<LI>
+Read the value of the Address/Data Register and save it for step 7.</LI>
+
+<LI>
+Output the index of the desired Data Register to the Address/Data Register</LI>
+
+<LI>
+Read the value of the Data Register and save it for later restoration upon
+termination, if needed.</LI>
+
+<LI>
+If writing, modify the value read in step 4, making sure to mask off bits
+not being modified.</LI>
+
+<LI>
+If writing, write the new value from step 5 to the Address/Data register.</LI>
+
+<LI>
+Write the value of Address register saved in step 1 to the Address/Data
+Register.</LI>
+
+<LI>
+If you wish to leave the register waiting for an index, input a value from
+the Input Status #1 Register (normally port 3DAh) and discard it.</LI>
+</OL>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If you have control over interrupts,
+then you can disable interrupts while in the middle of writing to the register.
+If not, then you may be able to implement a critical section where you
+use a byte in memory as a flag whether it is safe to modify the attribute
+registers and have your interrupt routine honor this. And again, it pays
+to be paranoid. Resetting the flip-flop even though it <B>should</B> be
+in the reset state already helps prevent catastrophic problems. Also, you
+might want to read back and compare the bytes written in step 3, 6, and
+7 as in the <A HREF="#paranoia">Paranoia</A> section above.
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; On the IBM VGA implementation,
+an undocumented register (CRTC Index=24h, bit 7) can be read to determine
+the status of the flip-flop (0=address,1=data) and many VGA compatible
+chipsets duplicate this behavior, but it is not guaranteed. However, it
+is a simple matter to determine if this is the case. Also, some SVGA chipsets
+provide the ability to access the attribute registers in the same fashion
+as the CRT, Sequencer, and Graphics controllers. Because this functionality
+is vendor specific it is really only useful when programming for that particular
+chipset. To determine if this undocumented bit is supported, perform the
+following procedure:
+<OL>
+<LI>
+Input a value from the Input Status #1 Register (normally port 3DAh) and
+discard it.</LI>
+
+<LI>
+Verify that the flip-flop status bit (CRTC Index 24, bit 7) is 0. If bit=1
+then feature is not supported, else continue to step 3.</LI>
+
+<LI>
+Output an address value to the Attribute Address/Data register.</LI>
+
+<LI>
+Verify that the flip-flop status bit (CRTC Index 24, bit 7) is 1. If bit=0
+then feature is not supported, else continue to step 5.</LI>
+
+<LI>
+Input a value from the Input Status #1 Register (normally port 3DAh) and
+discard it.</LI>
+
+<LI>
+Verify that the flip-flop status bit (CRTC Index 24, bit 7) is 0. If bit=1
+then feature is not supported, else feature is supported.</LI>
+</OL>
+<A NAME="color"></A><B>Accessing the Color Registers</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp; The color registers require an altogether
+different technique; this is because the 256-color palette requires 3 bytes
+to store 18-bit color values. In addition the hardware supports the capability
+to load all or portions of the palette rapidly. To write to the palette,
+first you must output the value of the palette entry to the PEL Address
+Write Mode Register (port 3C8h.) Then you should output the component values
+to the PEL Data Register (port 3C9h), in the order red, green, then blue.
+The PEL Address Write Mode Register will then automatically increment,
+allowing the component values of the palette entry to be written to the
+PEL Data Register. Reading is performed similarly, except that the PEL
+Address Read Mode Register (port 3C7h) is used to specify the palette entry
+to be read, and the values are read from the PEL Data Register. Again,
+the PEL Address Read Mode Register auto-increments after each triplet is
+written. The current index for the current operation can be read from the
+PEL Address Write Mode Register. Reading port 3C7h gives the DAC State
+Register, which specifies whether a read operation or a write operation
+is in effect. As in the attribute registers, there is guaranteed way for
+an interrupt routine to access the color registers and return the color
+registers to the state they were in prior to access without some communication
+between the ISR and the main program. For some workarounds see the <A HREF="#attribute">Accessing
+the Attribute Registers</A> section above. To read the color registers:
+<OL>
+<LI>
+Read the DAC State Register and save the value for use in step 8.</LI>
+
+<LI>
+Read the PEL Address Write Mode Register for use in step 8.</LI>
+
+<LI>
+Output the value of the first color entry to be read to the PEL Address
+Read Mode Register.</LI>
+
+<LI>
+Read the PEL Data Register to obtain the red component value.</LI>
+
+<LI>
+Read the PEL Data Register to obtain the green component value.</LI>
+
+<LI>
+Read the PEL Data Register to obtain the blue component value.</LI>
+
+<LI>
+If more colors are to be read, repeat steps 4-6.</LI>
+
+<LI>
+Based upon the DAC State from step 1, write the value saved in step 2 to
+either the PEL Address Write Mode Register or the PEL Address Read Mode
+Register.</LI>
+</OL>
+Note: Steps 1, 2, and 8 are hopelessly optimistic. This in no way guarantees
+that the state is preserved, and with some DAC implementations this may
+actually guarantee that the state is never preserved. See the <A HREF="vgadac.htm">DAC
+Operation</A> page for more details.
+
+<P><A NAME="binary"></A><B>Binary Operations</B>
+<BR><B>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </B>In order to better
+understand dealing with bit fields it is necessary to know a little bit
+about logical operations such as logical-and (AND), logical-or (OR), and
+exclusive-or(XOR.) These operations are performed on a bit by bit basis
+using the truth tables below. All of these operations are commutative,
+i.e. A OR B = B OR A, so you look up one bit in the left column and the
+other in the top row and consult the intersecting row and column for the
+answer.
+<BR>&nbsp;
+<CENTER><TABLE BORDER WIDTH="500" >
+<TR ALIGN=CENTER>
+<TD COLSPAN="3"><B>AND</B></TD>
+
+<TD></TD>
+
+<TD COLSPAN="3"><B>OR</B></TD>
+
+<TD></TD>
+
+<TD COLSPAN="3"><B>XOR</B></TD>
+</TR>
+
+<TR ALIGN=CENTER>
+<TD WIDTH="10%"></TD>
+
+<TD WIDTH="10%"><B>0</B></TD>
+
+<TD WIDTH="10%"><B>1</B></TD>
+
+<TD></TD>
+
+<TD WIDTH="10%"></TD>
+
+<TD WIDTH="10%"><B>0</B></TD>
+
+<TD WIDTH="10%"><B>1</B></TD>
+
+<TD></TD>
+
+<TD WIDTH="10%"></TD>
+
+<TD WIDTH="10%"><B>0</B></TD>
+
+<TD WIDTH="10%"><B>1</B></TD>
+</TR>
+
+<TR ALIGN=CENTER>
+<TD><B>0</B></TD>
+
+<TD>0</TD>
+
+<TD>0</TD>
+
+<TD></TD>
+
+<TD><B>0</B></TD>
+
+<TD>0</TD>
+
+<TD>1</TD>
+
+<TD></TD>
+
+<TD><B>0</B></TD>
+
+<TD>0</TD>
+
+<TD>1</TD>
+</TR>
+
+<TR ALIGN=CENTER>
+<TD><B>1</B></TD>
+
+<TD>0</TD>
+
+<TD>1</TD>
+
+<TD></TD>
+
+<TD><B>1</B></TD>
+
+<TD>1</TD>
+
+<TD>1</TD>
+
+<TD></TD>
+
+<TD><B>1</B></TD>
+
+<TD>1</TD>
+
+<TD>0</TD>
+</TR>
+</TABLE></CENTER>
+<BR>
+<A NAME="example"></A><B>Example Register</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The following table is an
+example of one particular register, the Mode Register of the Graphics Register.
+Each number from 7-0 represents the bit position in the byte. Many registers
+contain more than one field, each of which performs a different function.
+This particular chart contains four fields, two of which are two bits in
+length. It also contains two bits which are not implemented (to the best
+of my knowledge) by the standard VGA hardware.
+<BR>&nbsp;
+<TABLE BORDER WIDTH="600" CELLPADING="2" >
+<CAPTION ALIGN=TOP><B>Mode Register (Index 05h)</B></CAPTION>
+
+<TR ALIGN=CENTER VALIGN=CENTER>
+<TD WIDTH="75">7</TD>
+
+<TD WIDTH="75">6</TD>
+
+<TD WIDTH="75">5</TD>
+
+<TD WIDTH="75">4</TD>
+
+<TD WIDTH="75">3</TD>
+
+<TD WIDTH="75">2</TD>
+
+<TD WIDTH="75">1</TD>
+
+<TD WIDTH="75">0</TD>
+</TR>
+
+<TR ALIGN=CENTER VALIGN=CENTER>
+<TD WIDTH="75"></TD>
+
+<TD COLSPAN="2" WIDTH="150">Shift Register</TD>
+
+<TD WIDTH="75">Odd/Even</TD>
+
+<TD WIDTH="75">RM</TD>
+
+<TD WIDTH="75"></TD>
+
+<TD COLSPAN="2" WIDTH="150">Write Mode</TD>
+</TR>
+</TABLE>
+<BR>
+<A NAME="bitfields"></A><B>Masking Bit-Fields</B>
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Your development environment
+may provide some assistance in dealing with bit fields. Consult your documentation
+for this. In addition it can be performed using the logical operators AND,
+OR, and XOR (for details on these operators see the <A HREF="#binary">Binary
+Operations</A> section above.) To change the value of the Shift Register
+field of the example register above, we would first mask out the bits we
+do not wish to change. This is accomplished by performing a logical AND
+of the value read from the register and a binary value in which all of
+the bits we wish to leave alone are set to 1, which would be 10011111b
+for our example. This leaves all of the bits except the Shift Register
+field alone and set the Shift Register field to zero. If this was our goal,
+then we would stop here and write the value back to the register. We then
+OR the value with a binary number in which the bits are shifted into position.
+To set this field to 10b we would OR the result of the AND with 01000000b.
+The resulting byte would then be written to the register. To set a bitfield
+to all ones the AND step is not necessary, similar to setting the bitfield
+to all zeros using AND. To toggle a bitfield you can XOR a value with a
+byte with a ones in the positions to toggle. For example XORing the value
+read with 01100000b would toggle the value of the Shift Register bitfield.
+By using these techniques you can assure that you do not cause any unwanted
+"side-effects" when modifying registers.
+
+<P>Notice: All trademarks used or referred to on this page are the property
+of their respective owners.
+<BR>All pages are Copyright &copy; 1997, 1998, J. D. Neal, except where
+noted. Permission for utilization and distribution is subject to the terms
+of the <A HREF="license.htm">FreeVGA Project Copyright License</A>.
+<BR>&nbsp;
+<BR>&nbsp;
+</BODY>
+</HTML>