Close

Counting to 200

A project log for Novasaur CP/M TTL Retrocomputer

Retrocomputer built from TTL logic running CP/M with no CPU or ALU

alastair-hewittAlastair Hewitt 04/10/2019 at 18:160 Comments

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:

ModeBits per ColumnColumns
Hi-Res Graphics4320
Lo-Res Graphics8160
Text1680

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]
Font2 bits
Code Point (ASCII)8 bits
Foreground Color3 bits
Background Color3 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:

BinaryHexDecimalDescription
0011 10000x3856video RAM start
0011 10010x3957back porch end
0011 10100x3A58left border start
0011 10110x3B59left border end
0011 11000x3C60display start
1101 10110xDB219display end
1101 11000xDC220right border start
1101 11010xDD221right border end
1101 11100xDE222front porch start
1101 11110xDF223front porch & video RAM end
1110 00000xE0224H-Blank & H-Sync start
1111 01110xF7247H-Sync end
1111 10000xF8248back porch start
1111 11110xFF255H rco, H-Blank end

Discussions