The GPU does the same thing over and over again: Count to 200. It does this regardless of the graphics mode. Each horizontal scan will read 200 bytes of the RAM at the processor clock rate of 6.25 MHz. What does change is what each byte represents.
Even though the horizontal scan is 200 bytes long, it must also contain the border, overscan area, and sync timing. This extra stuff takes up 20% of the scan line, so only 160 bytes are typically displayed per line.
The 160 bytes is mapped to columns as follows:
Mode | Bits per Column | Columns |
---|---|---|
Hi-Res Graphics | 4 | 320 |
Lo-Res Graphics | 8 | 160 |
Text | 16 | 80 |
Each column in the graphics mode is directly mapped to a DAC. The hi-res 4-bit encoding is RGBI and the lo-res 8-bit encoding is RGB 3:3:2 (3-bits red and green, 2-bits blue). The text column contains two colors (foreground and background) and both use a 3-bit encoding of just RGB.
The 16 bits of a text column span 3 bytes and consists of the font, code point of the character, and two colors. The following table shows how these are mapped given a column index of C:
Byte[C-1] | Byte[C] | Byte[C+1] | |
---|---|---|---|
Font | 2 bits | ||
Code Point (ASCII) | 8 bits | ||
Foreground Color | 3 bits | ||
Background Color | 3 bits |
In addition to the 160 bytes per line for the conventional display area, an additional 4 bytes are added to the start and end of each line. These bytes would normally be set to a solid border color and are rendered along with the normal 160 bytes. These can be used to display content in the border, but this would only be visible on a CRT and wrap around the edge of the glass.
The display RAM provides up to 256 rows for the display. The total RAM required is 42k bytes with the 168 bytes reserved for each line for the display. The way this is mapped may seem a bit odd until you see the reasoning behind it.
The first column of the display (including the border) has an index of 56 (0x38 in hex). Remember we need to count to 200. A naive approach would be to start at 0 and count to 199 before returning to zero on the next clock pulse. If we start at 56 then the last index before reseting would be 255. The synchronous counter chips provide a signal (rco) that is generated on 255 and this can be used to reload the counter to 56. Therefore we count to 200, but without needing any additional logic gates (actually, one inverter)
So why place the border where it is? And why is it the size it is? The (VESA) VGA spec does specify a border, but this would only be 2 bytes (8 VGA pixels). The extra 2 bytes is added so the screen border ends at 224 (0xE0). This is when the H-Sync pulse begins. A single 3-input AND gate can be used to define the start of this pulse. This is the H-Blank signal and defines when the horizontal output should be turned off. The H-sync pulse lasts for 24 bytes, so a pair of 2-input NAND gates can fully define this when combined with the H-Blank signal.
Here's the detailed memory map of a line of video RAM:
Binary | Hex | Decimal | Description |
---|---|---|---|
0011 1000 | 0x38 | 56 | video RAM start |
0011 1001 | 0x39 | 57 | back porch end |
0011 1010 | 0x3A | 58 | left border start |
0011 1011 | 0x3B | 59 | left border end |
0011 1100 | 0x3C | 60 | display start |
1101 1011 | 0xDB | 219 | display end |
1101 1100 | 0xDC | 220 | right border start |
1101 1101 | 0xDD | 221 | right border end |
1101 1110 | 0xDE | 222 | front porch start |
1101 1111 | 0xDF | 223 | front porch & video RAM end |
1110 0000 | 0xE0 | 224 | H-Blank & H-Sync start |
1111 0111 | 0xF7 | 247 | H-Sync end |
1111 1000 | 0xF8 | 248 | back porch start |
1111 1111 | 0xFF | 255 | H rco, H-Blank end |
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.