017. A Look Back at the History of Graphics Cards — Part 1
Recently I studied the history of graphics cards, following the x86 thread as the backbone. Here is a rough summary.
The evolution of graphics cards can be divided into the following stages, which are also the major display modes:
- Text mode
- Color mode
- 3D mode
Text Mode
One can’t help but marvel at the compatibility of components across hardware generations: the earliest graphics cards only supported text mode, yet today’s newest graphics cards still support text mode right after initialization. Text mode, simply put, divides the screen into an M×N grid of cells; each cell has a coordinate, and at each coordinate a single character can be displayed.
Like this:

The graphics card of that era was called the Monochrome Display Adapter, abbreviated MDA.
At that time the CPU was still the 8086/8088. The CPU was simple, and the interface between the CPU and the display adapter was also simple — roughly a few address lines, a few data lines, plus some read/write control lines, interrupt lines, and the like:

It doesn’t look like many wires, but the card’s PCB looked the part, with gold-finger edge connectors to match:

This kind of display adapter is exactly the same as the most basic LCD controller that friends who play with microcontrollers carry around on their phones. It exposes a region of memory to the CPU, and that memory is also divided into M rows by N columns. Write a byte to the position of the corresponding row and column, and the character corresponding to that byte will appear at that coordinate on the screen. Write to a region of memory and content shows up on the screen — friends familiar with Linux may have thought of the frame buffer; that’s right, this corresponds to Linux’s framebuffer. This region of memory is what everyone casually calls video RAM (VRAM). It is mapped starting at address 0B0000h; it isn’t a chunk of physical memory, but rather a region of memory space that the display adapter exposes to the CPU through memory-mapped I/O.
So the MDA had to include a code table mapping bytes to characters. A better MDA monitor had multiple code tables — for example, when used by Russians it would swap in Russian letters and symbols. An even better MDA could let you define your own code tables. Each code table is called a code page. Does that sound a bit familiar? That’s right — the Windows cmd console settings panel also has a code page configuration option, and it serves exactly the same purpose as the MDA’s code page.
A code page might look like this:

The byte values corresponding to the characters above look like this:

It’s basically just ASCII.
How do you switch code pages? The MDA also exposes a few I/O ports to the CPU, which can be controlled via the in/out instructions:
03B0h, 03B2h, 03B4h, 03B6h: CRTC address register.
Write a CRTC register number (0 to 11h) to this port to select the CRTC register that will appear at port 03B5h. For details of the registers, see the6845 datasheet.
These addresses are partially decoded on a real MDA, so that any even- numbered address between 03B0h and 03B7h will get you the CRTC address register. But the official register to use is 03B4h.
This is a write-only register.
03B1h, 03B3h, 03B5h, 03B7h: CRTC register read/write.
This gives access to the selected CRTC data register. Most CRTC registers are write only; some are read/write or read-only. As with the address register, this is partially decoded; so although the official address is port 03B5h, it also appears at the other odd-numbered addresses between 03B0h and 03B7h.
03B8h: Mode Control Register
On a genuine MDA, this is a write-only register. Four of its bits can be set, but only two are any use:
Bit 5: 1 to enable blinking, 0 to disable it.
If bit 5 is 1, characters with attribute bit 7 set will blink. If not, they will have high intensity background.
Bit 3: 1 to enable video output, 0 to disable it.
If bit 3 is 0, screen output will not be shown. The usual use of this is if you’re reprogramming the CRTC registers; disable video output beforehand and re-enable it after.
Bit 1: 1 for black and white.
This bit has no meaning, since the MDA always outputs in monochrome. The value written to it is stored (in chip U58) but nothing else on the card pays any attention to it.
Bit 0: 1 for high resolution mode.
For any sane purpose this bit must be set to 1. For details of what happens if it is set to zero, seeHigh Resolution Mode.
Quite why the MDA implements bits 0 and 1 is not clear. Possibly IBM originally planned to make an expanded MDA that supported 40 columns and/or colour; or perhaps the CGA was designed first, and the MDA was based on the CGA design, including vestiges of the CGA’s 40-column and colour support. See alsocolour MDA.
03BAh: Status Register
This is a read-only register. Only two bits of the value read from this port are defined:
- Bit 3: Video. This is 1 if a green or bright green pixel is being drawn on the screen at this moment.
- Bit 0: Retrace. This is 1 if the horizontal retrace is active.
(On a real IBM MDA, bits 7-4 are always 1, and bits 2-1 are always 0).
Different manufacturers made various improvements to this kind of display adapter — for example, supporting more rows and columns, or color text — but none of these improvements changed things in any fundamental way.
Color Palette Mode
The MDA card in text mode could only display text; it gave no way to control the screen at the pixel level — you could only control things like making some 8×8 region display the letter A. To display anything different you had to modify the code table. Not convenient.
The Color Graphics Adapter that came later was much more useful. Because it could control things at the pixel level, it was called a graphics adapter. In English: CGA, Color Graphics Adapter.
It was used in essentially the same way as the MDA — it also mapped the video RAM, also called the frame buffer, into the CPU’s address space. For compatibility with the MDA, rather than starting at 0xB0000 it was offset by 8 KB to leave room for the MDA; its starting address is 0xB8000. The I/O space addresses also moved to 03D0h–03DFh.
The CGA still supported text mode, but it could also be switched to graphics mode through the I/O ports. In graphics mode the frame buffer was divided into M×N nibbles — a nibble being 4 bits, meaning it used 4 bits to control the display of one pixel. The meaning of the 4 bits is:
bit 3 = Intensity, Bit 2 = Red, Bit 1 = Green, Bit 0 = Blue
That is, it supported 16 colors. Those 16 colors were fixed.
The graphics card of this era still used the kind of interface shown above; there were just more address lines. A card looked roughly like this:

Friends who know a bit about image encoding may know that some images use a color palette, such as a 256-color palette. Although the number of colors supported doesn’t change, you can dynamically adjust which 256 colors those are. Some upgraded versions of the CGA supported a color palette, such as a 256-color palette where each pixel is represented by one byte, used to index a color in the palette.
Further-improved CGA cards supported full RGB888 color.
Okay, I’ll stop here for now. There’s still a lot more to write later, for example:
-
Introductions to more models of old graphics cards
-
Display buses such as ISA, VESA local bus, AGP
-
VESA BIOS Extension
-
3D graphics cards
-
AI chips
Comments