VGA Video Modes

Complete control of IBM's VGA system

Source: BYTE IBM Special Edition Fall 1988, physical page 191+
Author: Richard Wilton


The VGA is the video sub-system built into IBM's PS/2 Models 50, 60, and 80. It is also widely available as an adapter for the IBM PC XT and AT. In terms of capability and performance, the VGA is essentially a mildly improved version of the EGA. Surprisingly, however, the VGA is much more flexible than the EGA in terms of the resolution of the video modes that it can display, particularly when you use it with a variable-frequency video monitor.

Like the EGA, the VGA has several programmable control components, including a CRT controller (CRTC), a sequencer, an attribute controller, and a graphics controller. You can program each to modify essential timing signals and addressing modes within the video subsystem. The VGA's ROM BIOS contains a set of routines, invoked through interrupt 10 hexadecimal function 0, that program the VGA controllers into any of 24 different configurations (video modes).

Each of the VGA's controllers has a number of registers whose contents control their function. The VGA ROM BIOS contains tables of appropriate register values for each supported video mode, so most programmers call the ROM BIOS to select video modes instead of updating the registers directly. If, however, you want to create video modes unsupported by the video BIOS, you need to know what values to store in these registers to obtain the video configuration you want.

Why take the trouble to create your own video modes? The usual reason is to obtain higher-resolution graphics or more displayed text than the usual ROM BIOS video modes can provide. Some widely used commercial applications, including Microsoft Word and Lotus 1-2-3, can do this for you. If you want higher resolution in your own applications, however, you need to do some extra programming yourself.

Video Mode Control

You can differentiate video modes from each other in several ways:

  • Vertical resolution: number of rows of pixels (scan lines) displayed on the screen.
  • Horizontal resolution: number of characters or pixels per row.
  • Data representation in the video buffer.
  • Attribute decoding: colors, blinking, and so on.

When you program the VGA, you have a great deal of control over vertical and horizontal resolution. You have much less flexibility in regard to data representation and attribute decoding because of the VGA's hardware design. For this reason, the easiest way to set up alternative VGA video modes is to use the ROM BIOS mode-set routines to establish a baseline video mode, and then modify the horizontal and vertical resolution to produce a new video mode.

Video Display Timing

Controlling the resolution of the displayed image is -like many other activities in life- a matter of timing. Both horizontal and vertical resolution are related to the timing of the VGA's output signals that control the electron beam in the video monitor. The image on the video screen is not static, of course. It is produced by the cyclic sweep of the monitor's electron beam across and down the screen (see figure 1). The screen image is completely refreshed between 50 and 70 times per second, depending on the video mode.

Figure 1: On a video screen, the electron beam's scan cycle starts with the first pixel of the displayed video buffer data near the upper left corner of the screen. Scan lines are traced horizontally, left to right, then retraced down and across, right to left. In one scan line of a 640- by 480-pixel I6-color graphics mode, the horizontal total (100) specifies the duration of one complete horizontal scan cycle. Horizontal displayed (80) specifies the amount of displayed data. Horizontal sync starts at character clock 84 and lasts for 12 character clocks, so there are 4 characters of overscan at each end of the scan line. The vertical displayed (480) specifies the number of scan lines of displayed data. Vertical sync starts at scan line 503 and lasts for 2 scan lines, so there is a total of 42 scan lines of vertical overscan above and below the screen image.

As each scan line of pixels is displayed, the electron beam's intensity is modulated by signals generated by the VGA. (In a color monitor, there are three adjacent electron beams, one for each primary color, but for the purposes of video display timing, they can be regarded as a single beam.) The monitor moves the beam from left to right at a constant rate across each scan line and downward from scan line to scan line. The VGA generates a horizontal sync signal that controls when the monitor deflects the beam from the rightmost end of one scan line to the start of the next scan line (horizontal retrace). There is also a vertical sync signal that controls the deflection of the beam from the bottom of the screen back to the upper left corner (vertical retrace).

The VGA is always programmed so that the amount of time required to display data from the video buffer is less than the total amount of time it takes to sweep the electron beam horizontally and vertically. The extra time is spent in horizontal and vertical overscan. You can assign a color to the overscan area (also known as the border area) of the screen to provide a visual frame for the displayed video data, but that area's basic purpose is to center the displayed image on the screen.

You can control the horizontal timing signals generated by the VGA' s CRT controller by updating the appropriate CRTC registers. The timing values that you store in these registers are measured in "character clocks." A character clock corresponds to 8 pixels in VGA graphics modes and either 8 or 9 pixels in alphanumeric modes. You might want to think of a character clock as a unit of time (i.e., the time required to display one character's worth of data on the screen).

The key parameters that control horizontal timing are as follows:

  • Horizontal total. The total amount of time spent in displaying each scan line, including the time required for horizontal retrace.
  • Horizontal displayed. The number of character clocks of data displayed from the video buffer in each scan line. The difference between the horizontal total and the horizontal displayed parameters describes the amount of horizontal overscan.
  • Horizontal sync. The character clock at which the horizontal sync pulse begins.

The timing parameters that control the vertical size and on-screen location of the displayed image are analogous to those that control horizontal timing. Vertical timing parameters are usually specified in terms of number of scan lines. As with character clocks, you might want to consider a scan line to be a unit of time (i.e., the amount of time it takes to draw one scan line on the screen and return the electron beam to the beginning of the next scan line).

Here are the vertical timing parameters you need to consider when you establish a VGA video mode:

  • Vertical total. The total number of scan lines in one complete refresh cycle.
  • Vertical displayed. The number of scan lines of data displayed on the screen. The difference between the vertical total and the vertical displayed parameters determines the amount of vertical overscan.
  • Vertical sync. The scan line in which the vertical sync pulse begins.

VGA Timing Constraints

In order to use these general timing parameters to program the VGA, you need to know the basic timing frequencies used by the VGA and by your video monitor. There are three different control-signal frequencies or rates to consider: The rate at which pixels are displayed, the rate at which the electron beam sweeps across the scan lines, and the rate at which the entire screen image is refreshed. These three rates are commonly called the dot rate, the horizontal scan rate, and the vertical scan rate.

  • Dot rate. The rate at which the video subsystem displays pixels is called its dot rate; this frequency is also known as the pixel rate or the video bandwidth. This rate is established by a high-frequency crystal oscillator called the dot clock. You can program the VGA to use one of several dot clocks with different frequencies. Two different crystal oscillators are built into the VGA with frequencies of 25.175 MHz and 28.322 MHz; you can select a third oscillator from the auxiliary video connector on the system board of a PS/2 Model 50, 60, or 80.

  • Horizontal scan rate. The horizontal scan rate is the number of scan lines displayed per second. When you program the VGA, you indirectly specify a horizontal scan rate by specifying the total number of pixels contained in each scan line. If you divide the dot-clock frequency by the total number of pixels per scan line, you get the horizontal scan rate.

  • Vertical scan rate. The vertical scan rate (also called the refresh rate or frame rate) is the number of times per second that the screen is refreshed. You determine the vertical scan rate by programming the VGA to display a specified number of scan lines during each refresh cycle. You can calculate the vertical scan rate by dividing the horizontal scan rate by the number of scan lines per frame.

The key to establishing alternative VGA video modes lies in programming the VGA to produce timing signals that fall within the limitations of your monitor. When you set up a video mode by programming the VGA, you must select a dot rate, horizontal scan rate, and vertical scan rate that lie within the tolerances of the monitor you're using. I've listed the tolerances of a few VGA-compatible monitors in table 1.


Table 1: Tolerances of a few VGA-compatible monitors

For example, consider the default ROM BIOS video mode 12h-that is, 640- by 480- pixel 16-color graphics mode. This mode is designed to work with IBM's PS/2-compatible monitors, which expect a horizontal scan rate of 31.5 KHz. The BIOS uses the VGA's 25.175-MHz dot clock in this video mode, so you can easily determine the relevant timing constraints.

To compute the horizontal total, you divide the dot rate by the horizontal scan rate to obtain the number of pixels per scan line. Then you divide this value by 8 (the number of pixels per character clock) to determine the number of character clocks per scan line:

Horizontal total = (25175000/31500)/8 = 100 character clocks

Since each scan line contains 640 pixels of data, the horizontal displayed parameter is 640 divided by 8, or 80. The extra 20 character clocks represent the time spent in horizontal overscan and in horizontal retrace. To center the displayed pixel data, the horizontal sync signal starts at the eighty-fourth character clock, and the horizontal sync pulse lasts for 12 character clocks. The result is a scan line with 4 character clocks of overscan at each end.

The ROM BIOS relies on similar calculations to determine the vertical timing parameters. The BIOS sets up this video mode so that 60 frames are displayed per second. This vertical scan rate lies in the middle of the tolerance range of IBM's PS/2 video monitors. The vertical total, measured in scan lines, is the quotient of the actual horizontal scan rate (scan lines per second) and the desired vertical scan rate of 60 frames per second:

Vertical total = (25175000/(100 x 8)) / 60 = 524 scan lines

The vertical displayed parameter is 480, the number of rows of pixel data that are displayed in this video mode. The remaining 44 scan lines represent vertical overscan plus the time required for vertical retrace. The BIOS starts vertical retrace after 503 scan lines and specifies the duration of the vertical sync pulse to be 2 scan lines. Thus, the 480 scan lines of video data are displayed with a total of 42 (524-480-2) scan lines of vertical overscan above and below.

Video-Mode Programming

Once you decide what the horizontal and vertical timing parameters will be for a video mode, you can program the VGA to display it. There are five tasks you must perform to coordinate the different components of the VGA subsystem:

  • Program the CRTC.
  • Program the sequencer.
  • Select a dot-clock frequency.
  • Specify the displayed character height.
  • Update relevant ROM BIOS variables.

You program the VGA's controllers through a set of I/O ports (see table 2). You must access these ports with either assembly language IN and OUT instructions or their high-level-language equivalents. To access the ROM BIOS, you need to execute interrupt 10h, either directly in assembly language or through a high-level-language construct such as the int86( ) function in Microsoft C.


Table 2: I/O ports used for VGA control.

Most of the VGA's control over the horizontal and vertical timing parameters is obtained through the CRTC. The CRTC controls the duration of the horizontal and vertical timing signals sent to the monitor. It also synchronizes the timing signals with the rate that data is extracted from the video buffer and processed by the display circuitry. You control these functions by updating the appropriate CRTC registers (see table 3).


Table 3: VGA CRT controller registers used for video-mode programming

To update a CRTC register, you must write a register number to I/O port 3D4h and then write the register's new value to port 3D5h (see listing 1).


Listing 1: Updating a CRTC register

There are a couple of tricks to CRTC programming on the VGA. First, you can use a single 16-bit port write to obtain the same results:

;AL = register number
mov al,RegNumber
;AH = new register value
mov ah,RegValue
mov dx,3D4h
;Write to port 3D4h/3D5h
out dx,ax

If you don't use 8-bit port accesses, be sure to clear the interrupts. Otherwise, a hardware interrupt may occur between the port writes and disrupt your program by transferring control to a service routine that does its own CRTC programming.

Also, if you're programming in ROM BIOS modes 7 or 0Fh, use ports 3B4h and 3B5h instead of 3D4h and 3D5h. These port addresses mimic those that are used in the Monochrome Display Adapter; they let you operate both a VGA and another color video subsystem in the same computer.

Unlike the control registers in previous IBM video subsystems, you can perform both reads and writes to the VGA' s control registers (see listing 2). This is particularly convenient because it lets you save the current state of the CRTC registers before you modify them.


Listing 2: Unlike previous cards, VGA control registers can be read and written

The VGA sequencer has several interrelated functions, including synchronization of the video subsystem's character clock with the dot clock. The character clock determines the rate at which bytes of data from the video buffer are displayed. You can set the character clock so that one character is displayed every 8 or 9 ticks of the dot clock. In other words, each byte of data in the video buffer may be displayed as either 8 or 9 horizontal pixels, depending on how you program the sequencer.

In default VGA alphanumeric modes, the VGA displays 9 pixels for each character on the screen. In EGA-compatible 350-line alphanumeric modes and in graphics modes, the system programs the sequencer to display 8 pixels per character. The extra (ninth) pixel increases the sharpness of displayed text, but omitting the extra pixel allows you to display more characters across the screen.

You would access sequencer registers through I/O ports 3C4h and 3C5h (see table 4). The same programming techniques I've shown to access the CRTC will work for accessing the sequencer registers, but there is a catch: When you select a new dot clock or change the number of pixels per character, you must temporarily reset the sequencer by toggling bit 1 of its reset register. An example of this is in listing 3, which programs the sequencer to generate 8 pixels per character.


Table 4: VGA sequencer registers used/or video-mode programming


Listing 3: Programming VGA sequencer to produce 8 pixels per character

Bits 2 and 3 of the VGA's miscellaneous output register specify which dot clock frequency to use (see table 5). You can update this register by reading I/O port 3CCh to obtain its current value, masking bits 2 and 3, and then writing port 3C2h. When you do this, however, you should temporarily reset the sequencer, as in the previous program example.


Table 5: VGA dot-clock selection via miscellaneous output register (I/0 port 3C2h).

In default alphanumeric modes, the video BIOS configures the VGA to display 25 rows of characters. For example, in 400-line alphanumeric modes (the power-on default), each character is 16 scan lines high. You can modify any alphanumeric mode to display more than 25 rows of characters simply by using shorter characters that are displayed in fewer scan lines.

Bits 0 through 4 of CRTC register 09h, the maximum scan-line register, control the displayed height of alphanumeric characters. The value in this bit field is one less than the character height in scan lines. Thus, in default alphanumeric modes, the value in bits 0 through 4 is 01111 binary (0Fh). If, for example, you change this value to 00111 binary (07h), the CRTC would display only 8 scan lines per character, so you would have a video mode that consisted of 50 character rows instead of 25.

Although you can update the maximum scan-line register directly, it is usually better to use the ROM BIOS to do the work for you. The ROM BIOS provides considerable flexibility in setting the displayed height of alphanumeric-mode characters because it lets you select an appropriate character set at the same time. For example,

;AH = 11h (ROM BIOS function number)
;AL = 12h (sub function number)
mov ax, 1112h
mov bl,0
;Call the video BIOS
int 10h

This sequence calls the video BIOS to display a character set in which each character is only eight scan lines high. The BIOS loads the character set into the hardware character generator, programs the CRTC appropriately, and updates its global data area with the new number of character rows displayed.

Two Examples

I've created two programs that automate the process of calculating the CRTC register values for different video modes. (I used Microsoft C 5.0 to compile these programs. If you use another vendor's C compiler, you may need to rewrite the references to the int86() library call that invokes interrupt 10h.) The alphanumeric-mode program, AVMODE, lets you specify the number of displayed character columns, the size of the displayed character matrix, and an optional horizontal adjustment factor that helps to center the screen image. For example, you can create a 90-column mode that uses 8 by 8 characters by running the program with this command:

AVMODE 90 8 8

If the resulting image is not centered horizontally, you can also specify an adjustment to the horizontal sync position. For instance, you could shift the image one character position rightward by executing the program with the following:

AVMODE 90 8 8-1

The program uses the video BIOS character-generator interface to give the CRTC the specified height of the character matrix. It then programs the sequencer to display characters that are either 8 or 9 pixels wide. The rest of the program sets up the CRTC with horizontal timing parameters appropriate for the number of characters to be displayed.

For simplicity, AVMODE.C performs all its sequencer and CRTC programming in high-level subroutines. In practice, however, you should probably use assembly language to do this. The reason is that the C functions inp( ) and outp( ) compile as subroutine calls instead of in-line IN and OUT instructions. This means that subroutines that call inp( ) and outp( ) (e.g., SetSeqReg( ) and SetCRTCReg( )) are somewhat lengthy and too susceptible to interference from hardware interrupts to be thoroughly reliable.

You will find that an IBM VGA (in a PS/2 Model 50, 60, or 80) or IBM VGA adapter can produce an alphanumeric mode with about 96 8-pixel characters per row using an IBM PS/2 monitor. Higher resolutions exceed the tolerances of IBM's monitors.

If you use a variable-frequency monitor, you can push the VGA up to 132 characters per row. (Of course, the characters are pretty tiny when you squeeze 132 in a row.) You will probably have to adjust the vertical hold control on your monitor, because the vertical scan rate with a 132-character alphanumeric mode is only 51.5 Hz. Also, you may notice that the screen image flickers when you display a large, bright field of color; this, too, is a consequence of the low vertical scan rate.

Use the PC-DOS CLS command with caution if you use AVMODE to change the number of displayed character rows. The video BIOS keeps track of the number of character rows in a byte in its global data area at address 0040:0084h, but PC-DOS ignores this value and assumes that there are always 25 rows of data to clear. If you program the CRTC to display 50 lines of data, CLS clears only the top half of the screen. To avoid this problem, you could write your own screen-clear command (see listing 4), using interrupt 10h function 6.


Listing 4: A custom screen-clear program

GVMODE, the graphics-mode example, requires you to specify the number of pixels to be displayed horizontally and vertically. For example, to set up a 720-by 480-pixel 16-color graphics mode, you execute GVMODE as follows:

GVMODE 720 480

The program uses the desired resolution to select which of the VGA' s dotclocks to activate. This lets GVMODE produce a wider range of video modes than it could if it relied on just one dotclock frequency. Apart from these small differences, however, GVMODE's operation is similar to that of AVMODE.

With an off-the-shelf IBM VGA and PS/2-compatible monitor, you can use GVMODE to produce a graphics mode with about 720- by 512-pixel resolution, although displaying this many pixels pushes IBM's analog monitors to their limits. However, 800- by 600-pixel resolution is well within the tolerances of a non-IBM variable-frequency monitor.

Again, higher resolutions imply lower vertical scan rates. You may find that the resolution you want to use in your programs is limited by the amount of perceptible flicker on the screen at lower vertical scan rates. [Editor's note: The source code for AVMODE.C and GVMODE.C is available in a variety of formats.]

VGA Clones

The ICs that IBM used in the VGA subsystem are proprietary. IBM's competitors have been forced to reverse-engineer the VGA hardware to produce the same capabilities in their own products. This means that a VGA clone may not necessarily be hardware-compatible with an IBM VGA. Two ways the clones may differ are in the values stored in the control registers and in the dot-clock frequencies you can use.

The register-programming techniques I've described are not applicable to all VGA subsystems because not all VGA clone makers have designed their CRT controllers to use the same register values as IBM's. For example, when you try to program the CRTC on Video Seven's VEGA VGA, you'll discover that many of the CRTC registers require different values than they do with a true-blue IBM VGA. Other adapters, including the Paradise VGA Plus, expect the same register values as an IBM VGA, so programming these clones is much easier.

Manufacturers of VGA clones generally implement higher-resolution, non-IBM video modes using a higher-frequency dot clock. For example, the Paradise VGA Plus uses a 36.000-MHz dot clock in 132-column alphanumeric modes and in 800- by 600-pixel graphics modes. With the higher dot-clock rate, the resulting horizontal and vertical scan rates in these modes are higher than they are when you use a true-blue VGA's 28.322-MHz dot clock. The scan rates are much closer to the middle of the tolerance range of most monitors, and the increased vertical scan rate results in less flicker.

Alternative Video Modes

Clearly, these alternative VGA video modes are not for everybody. Using them requires some understanding of how the video subsystem works. However, if you're writing a program that does fullscreen text or graphics output, you should be able to incorporate support for alternative video modes without too much anguish.

On the other hand, alternative video modes are rarely supported by off-the-shelf software. Making your favorite spreadsheet or word processor run in an alternative video mode might require you to customize the program's installation process. If you use a VGA clone with a BIOS that supports non-IBM video modes, you might be able to include special drivers provided by the clone's manufacturer when you install your software. Otherwise, you may need to patch an existing driver or write your own driver in order to exploit an alternative video mode.

Nevertheless, there is a reasonable amount of support in the VGA hardware and video BIOS for alternative video modes. If you program the hardware carefully and exploit the services offered in the ROM BIOS, you can run applications with higher resolution or more characters than the usual ROM BIOS video modes provide.


Richard Wilton is the author of Programmer's Guide to PC and PS/2 Video Systems and coauthor of The New Peter Norton Programmer's Guide to the PC and PS/2, both published by Microsoft Press. He lives in Los Angeles, California, and he can be reached on BIX c/o "editors."

Content created and/or collected by:
Louis F. Ohland, Peter H. Wendt, David L. Beem, William R. Walsh, Tatsuo Sunagawa, Tomáš Slavotínek, Jim Shorney, Tim N. Clarke, Kevin Bowling, and many others.

Ardent Tool of Capitalism is maintained by Tomáš Slavotínek.
Last update: 14 Apr 2024 - Changelog | About | Legal & Contact