A few weeks ago I had a sudden need to understand certain finer points of the operation of EGA/VGA BIOS. I found common reference materials to be inadequate—they tend to do a good job of documenting the data structures the video BIOS uses, but do not even attempt to explain what those structures are for and how exactly the video BIOS uses them.
Partly it’s IBM’s fault. The technical references covering VGA products did not quite explain everything in detail either. For the EGA, IBM solved the BIOS documentation problem the old-fashioned way—by publishing the complete BIOS listing.
Now, the EGA BIOS listing included a fairly decent documentation of the INT 10H interface as part of the source code itself (IBM had previously done the same thing with the PC/XT/AT system BIOS). Decent documentation but not great. But naturally anyone who needed to know more could just read the BIOS listings! For the VGA, BIOS listings were never published, although the VGA BIOS did not do too much new that the EGA didn’t do already.
For answering my questions, the EGA BIOS listings were sufficient. Except the available documents weren’t terribly well OCRed and thus were difficult to search properly. That is mostly IBM’s fault too—the listings were printed in rather small font. It’s not hard to see why IBM did that: Even at about 130 lines per page, the EGA BIOS runs over 60 pages of dense text!
To avoid any problems with searching the BIOS listings, I decided to reconstruct the source code of the EGA BIOS from the published listings, using the poorly OCRed text as a basis.
Verifying the reconstructed source code was trivial: If the reassembled BIOS matches an actual EGA BIOS, it must be close enough to the original.
From the published listings it is not clear what assembler IBM used. It must have been some version of MASM, but we can only guess which. As it turns out, the EGA BIOS was written in a fairly straightforward way without using any MASM “cleverness”, and can therefore be successfully assembled with almost any version of MASM.
I found out that just about any version of MASM from 1.0 up to and including 4.01 produces the same binary. Only MASM 5.0/5.1 is a little smarter and produces different code. Obviously MASM 4.0 is too new, and perhaps even 3.0 is. It’s entirely possible or even likely that IBM MASM 1.0 was used for the EGA BIOS, but it could just as easily have been some other version.
The EGA BIOS was split into several separately compiled modules, and the main module with most of the code was further divided into a number of INCLUDEd source files. The names of the .INC files are apparent from the published listings, though the names of the modules are not.
The listings also do not indicate how the modules were linked. Not coincidentally, the listings of the modules appear in the same order in which the modules were linked. It is thus not difficult to reconstruct a method to assemble and link the source modules, and then run them through EXE2BIN.
Note that the result won’t be an exact match of an EGA BIOS image. To reproduce the EPROM contents, the BIOS image would have to be padded to the appropriate size (16 KB) and equipped with the correct checksum. For my purposes, that was unnecessary because I only needed to make sure that my EGA BIOS binary, which is 14,688 bytes long, matches the first 14,688 bytes of the EGA BIOS dump. And it does.
I attempted to reproduce the EGA BIOS source code as accurately as possible, which means including any typos, misspellings, or grammatical errors. I ran into one annoying but non-critical problem: The published EGA BIOS listings use a font where capital letter O and the number zero (0) are either identical or, more likely, indistinguishable given the small size and print/scan quality. Most of the time, it’s obvious which is which, but in a couple of instances (mostly function names or labels) it is not clear from context whether capital O or zero was in the original. But whichever it was, the naming is consistent in the reconstructed source and does not hamper searchability.
There are two copies of the bulk of the EGA BIOS source code (basically everything minus fonts). The file EGABIG.ASM is one flat file containing (almost) everything. It has one very important property: The line numbers in EGABIG.ASM exactly match the line numbers in the Tech Ref listing. That way, source location can be easily cross-referenced.
The “real” source code is in VBIOS.ASM which includes 9 other files with the .INC extension. Those files are meant to represent what the source code really looked like.
The source code archive can be downloaded or viewed online. If you find any errors (and I’m sure there are a few), feel free to report them in a comment. But first please check the Tech Ref listing first, because there are plenty of typos and misspellings in the original.
While reading the EGA BIOS source code, I learned that like the VGA, the EGA can operate as either a color or a mono adapter. But unlike VGA, which can dynamically switch between mono and color, the EGA’s behavior depends on the type of the attached monitor and won’t change at runtime. The reason for that is that the EGA could work with existing IBM MDA and CGA monitors (models 5151 and 5153, respectively), as well as a “native” EGA monitor (model 5154).
And, again unlike the VGA, the EGA also limits the text and graphics mode choice depending on the attached monitor, which can display either 200 (CGA) or 350 (EGA/MDA) lines and nothing else. The VGA can display either 400/200 (the latter double-scanned) or 350 lines in alphanumeric modes; VGA text modes can thus use 8, 14, or 16 pixels high fonts, whereas EGA has to use either 8 or 14 pixels depending on the monitor.
The EGA, like the VGA, can use 9-pixel wide text mode characters. But unlike VGA, the EGA can do so only when using a monochrome MDA style monitor with 720-pixel horizontal resolution. Like the VGA, the EGA BIOS contains an 8×14 pixel font which is suitable for modes with 8-pixel wide character box; for running with 9-pixel wide characters, there is a “patch table” which the BIOS uses to overwrite a handful of characters that benefit from a bitmap optimized for 9-pixel wide box (particularly wide/complex letters such as ‘M’ or ‘W’).
The real reason I wanted to read the listing was the video parameter/save area usage. The format is well documented, the usage is not. The BIOS initially sets up the pointer at 40:A8 in the BDA to point at the default table in ROM.
When the BIOS executes a mode set, it looks at the pointer in the BDA and uses that to locate the mode parameter tables. Depending on whether it’s setting a text or graphics mode, the BIOS looks at the alphanumeric or graphics font override table. The font overrides are used only during a mode set.
Since the default parameter/save table is in ROM, it is obvious that if anyone wants to customize it, they need to copy the one in ROM (or rather whatever 40:A8 points at), modify it, and update the pointer in the BDA.
There is also a dynamic save area which is used for storing the content of palette registers on the EGA/VGA. This save area is written (rather than read) by the BIOS during a mode set if the dynamic save pointer area is non-null. But it is also read and written by some INT 10h/10h subfunctions, again only when the dynamic save area pointer is non-null. And in the default case of a ROM parameter/save table, it will be.
There was a clear technical reason for the save area: To the chagrin of programmers, most of the EGA registers were write-only. Software which needed to implement any kind of screen switching couldn’t just read the hardware state. The save area kept track of palette state, both during the initial mode set and in INT 10h/0Bh and INT 10h/10h calls. Note that the EGA BIOS did not offer a service to read the current palette state, precisely because the dynamic save area was optional; by default, the BIOS simply had no way to determine the current state.
Overall, the BIOS usage of the parameter/save table is fairly straightforward, yet sufficiently non-obvious that it is impossible to figure out from incomplete documentation.