X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pintos-anon;a=blobdiff_plain;f=specs%2Ffreevga%2Fvga%2Fvgareg.htm;fp=specs%2Ffreevga%2Fvga%2Fvgareg.htm;h=45d31626c77d410432816ce0c9a0bf2fcb66f0ec;hp=0000000000000000000000000000000000000000;hb=8af06d1fd50343e17229618ef4d2693193b2b3d9;hpb=d0d14ca50fbac167253e1e1d8d806bfd749a5e8a diff --git a/specs/freevga/vga/vgareg.htm b/specs/freevga/vga/vgareg.htm new file mode 100644 index 0000000..45d3162 --- /dev/null +++ b/specs/freevga/vga/vgareg.htm @@ -0,0 +1,508 @@ + + + + + + + VGA/SVGA Video Programming--Accessing the VGA Registers + + + +
Home Intro Advice +Fudge Paranoia External +Indexed Attribute Color +Binary Example Masking +Back  +
Hardware Level VGA and SVGA Video Programming Information +Page
+ +
Accessing the VGA Registers  +
+ + +Introduction +
        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. + +

General Advice +
        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. + +

I/O Fudge Factor +
        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.) + +

Paranoia +
        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. + +

Accessing the External Registers +
        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. + +

Accessing the Sequencer, Graphics, and CRT +Controller Registers +
        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: +

    +
  1. +Input the value of the Address Register and save it for step 6
  2. + +
  3. +Output the index of the desired Data Register to the Address Register.
  4. + +
  5. +Read the value of the Data Register and save it for later restoration upon +termination, if needed.
  6. + +
  7. +If writing, modify the value read in step 3, making sure to mask off bits +not being modified.
  8. + +
  9. +If writing, write the new value from step 4 to the Data register.
  10. + +
  11. +Write the value of Address register saved in step 1 to the Address Register.
  12. +
+        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 Paranoia 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 Enable Vertical Retrace Access +and CRTC Registers Protect Enable fields. +Ensuring that access is not prevented even if your card does not normally +protect these registers makes your + +

Accessing the Attribute Registers +
         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: +

    +
  1. +Input a value from the Input Status #1 Register (normally port 3DAh) and +discard it.
  2. + +
  3. +Read the value of the Address/Data Register and save it for step 7.
  4. + +
  5. +Output the index of the desired Data Register to the Address/Data Register
  6. + +
  7. +Read the value of the Data Register and save it for later restoration upon +termination, if needed.
  8. + +
  9. +If writing, modify the value read in step 4, making sure to mask off bits +not being modified.
  10. + +
  11. +If writing, write the new value from step 5 to the Address/Data register.
  12. + +
  13. +Write the value of Address register saved in step 1 to the Address/Data +Register.
  14. + +
  15. +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.
  16. +
+        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 should 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 Paranoia section above. +
        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: +
    +
  1. +Input a value from the Input Status #1 Register (normally port 3DAh) and +discard it.
  2. + +
  3. +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.
  4. + +
  5. +Output an address value to the Attribute Address/Data register.
  6. + +
  7. +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.
  8. + +
  9. +Input a value from the Input Status #1 Register (normally port 3DAh) and +discard it.
  10. + +
  11. +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.
  12. +
+Accessing the Color Registers +
     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 Accessing +the Attribute Registers section above. To read the color registers: +
    +
  1. +Read the DAC State Register and save the value for use in step 8.
  2. + +
  3. +Read the PEL Address Write Mode Register for use in step 8.
  4. + +
  5. +Output the value of the first color entry to be read to the PEL Address +Read Mode Register.
  6. + +
  7. +Read the PEL Data Register to obtain the red component value.
  8. + +
  9. +Read the PEL Data Register to obtain the green component value.
  10. + +
  11. +Read the PEL Data Register to obtain the blue component value.
  12. + +
  13. +If more colors are to be read, repeat steps 4-6.
  14. + +
  15. +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.
  16. +
+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 DAC +Operation page for more details. + +

Binary Operations +
        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. +
  +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ANDORXOR
010101
000001001
101111110
+
+Example Register +
        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. +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mode Register (Index 05h)
76543210
Shift RegisterOdd/EvenRMWrite Mode
+
+Masking Bit-Fields +
        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 Binary +Operations 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. + +

Notice: All trademarks used or referred to on this page are the property +of their respective owners. +
All pages are Copyright © 1997, 1998, J. D. Neal, except where +noted. Permission for utilization and distribution is subject to the terms +of the FreeVGA Project Copyright License. +
  +
  + +