First post, by riplin
- Rank
- Newbie
Hi folks, I'm working on some VGA/SVGA programming (in particular, Matrox video cards).
I'm trying to understand the workings of all the registers in the CRT, Sequencer, etc. I figured that trying to translate those values back to human readable form that make sense when looking at timing documentation would be a good start.
So far, I've gotten most of the values to work, but I'm having some problems with the horizontal start / end blanking values. Here's an example for the blank start using 1600x1200@60Hz:
Standard VGA data from BIOS (in BDA format):
{
0x50, // Number of character columns
0x0B, // Number of screen rows - 1
0x08, // Character height in pixels
0x2000, // Video buffer size
{ 0x01, 0x0F, 0x00, 0x0E }, // Sequencer controller registers, starting at SR01
0x2F, //Miscellaneous output register
{ 0x09, 0xC7, 0xC7, 0x0D, 0xCF, 0x07, 0xE0, 0x00, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x23, 0xAF, 0xC8, 0x00, 0xAF, 0xE1, 0xC3, 0xFF }, //CRT controller registers starting at CR00
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x41, 0x02, 0x0F, 0x00 }, //Attribute controller registers starting at AR00
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF } //Graphics controller registers starting at GR00
};
Matrox specific registers:
Horizontal counter extensions (CREXT01): 0x01
Vertical counter extensions (CREXT02): 0x2D
All the horizontal timings are in character clocks, so we need to know how many pixels there are to a character clock. This can be either 8 or 9 pixels.
The dot clock select is located in SR01<0> (Sequencer register 1, bit 0). SR01 = 0x01. Bit 0 is set to 1 and according to the docs that means a dot clock of 8. 8 pixels per character. Great.
I'm going to need horizontal display end to show the issue. This one lives in CR01, with a value of 0xC7. The docs say we need to add 1 to this to get the actual value used, so 0xC8 it is. In decimal that's 200. Multiply by the dot clock of 8 and we get a grand total of 1600 pixels.
Start horizontal blank lives in CR02 with a value of 0xC7, with an extension bit in CREXT01<1>. CREXT01 = 0x01, so bit 1 is 0, which leaves our value at 0xC7, which is 199 decimal and times 8 = 1592 pixels... Wait. Less than 1600? Was I supposed to add 1 here as well? Not according to the docs, so this is a bit confusing. Does Horizontal display end supersede this value? Why not just make them the same value?
The annoying part is, that it's not all modes. Some of them do have the same horizontal display end value and horizontal blank start value after conversion.
Here's the issue I have with horizontal blank end. This is the only mode that has a weird value.
80x60@59Hz (rendered as 640x480):
{
0x50, // Number of character columns
0x3B, // Number of screen rows - 1
0x08, // Character height in pixels
0x2580, // Video buffer size
{ 0x01, 0x03, 0x00, 0x02 }, // Sequencer controller registers, starting at SR01
0xEF, //Miscellaneous output register
{ 0x60, 0x4F, 0x50, 0x83, 0x52, 0x9E, 0x0B, 0x3E, 0x00, 0x47, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x8C, 0xDF, 0x28, 0x1F, 0xE6, 0x06, 0xA3, 0xFF }, //CRT controller registers starting at CR00
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x0C, 0x00, 0x0F, 0x00 }, //Attribute controller registers starting at AR00
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x00, 0xFF } //Graphics controller registers starting at GR00
};
Matrox specific registers:
Horizontal counter extensions (CREXT01): 0x00
Vertical counter extensions (CREXT02): 0x00
Horizontal total is stored in CR00, which is 0x60, an extra bit lives in CREXT01<0>, but the entire register is 0x00, so nothing to add. Result ix 0x60 + 5 due to register quirk, decimal that's 101, times 8, is 808 pixels.
Horizontal start blank, again, lives in CR02 value is 0x50, with an extension bit in CREXT01<1>, which is 0, so final value is 80 decimal, or 640 in pixels. (see how this one matches the vertical resolution instead of 8 less?)
Horizontal blank end lives in CR03, which is 0x83. Only the lowest 5 bits count, so we and with 0x1F, giving us 0x03. CR05<7>, value 0x9E has bit 5, which is 1, so we get 0x23. Finally, bit 6 lives in the extension register CREXT01<6>, which is 0x00, so nothing to gain there. We have 7 bits total, making our correction factor 0x80 (lowest bit above our value). With a value of 0x23, it is less than the hblank start value of 0x50, (since we are looking for hblank start + hblank duration) so we add 0x80 to our value, giving 0xA3, which is 163 in decimal, or 1304 in pixels... which is waaaay, to0 high compared to the 808 horizontal total.
What am I missing?
Any help would be greatly appreciated.