Microelectronics | VGA ROM Fonts


I once had a Chips and Technologies ISA VGA card that had an interesting ROM font. Then I had another very interesting ATI EGA card with a beautiful font. And now I have an ATI VGA Wonder 16 with a very appealing font. The fact is that all these three ISA cards were very slow. I sold the first two cards and kept the ATI VGA Wonder 16 though. From time to time, I miss the Chips and Technologies card. For some reason, the PC was always throwing an audible VGA error beep-code, but it worked perfectly without any hassles. Anyway, let's come back to modern times. My DIY System Design adventures require a fast ISA VGA card. Thus, I bought a new (!) old stock (and pricey, too) Tseng Labs ET4000/W32i equipped with 2 Mb RAM from a guy called Ted Allen, owner and designer at Micro-Labs, Inc in the U.S.A. This card works perfectly. I can play any MS-DOS game, including Quake at 320 x 200 without any problems. However, since I still do a lot of MS-DOS programming, I often find myself lusting for the fonts of the cards on which I learned programming. And the Tseng Labs card has a monotone (read, quasi-boring) modern and common ROM font. It's not as bad as the fonts of the PCI cards, but still.


VGA ROM fonts cannot be replaced that easily. However, there is a quick method that allows you to upload a custom font into the VGA RAM. This is done by means of a small TSR program that forces the card to always use the custom font. But for some reason, after running some MS-DOS programs that install their own fonts (think HWiNFO, NSSI, NU) or some graphics mode programs, the TSR fails and the card reverts to the original ROM font. Furthermore, this TSR occupies 4096 bytes of RAM for the font data and another 368 bytes for the program code. To solve the conventional memory issue, I loaded this TSR high in AUTOEXEC.BAT. Now those 4.3 Kb are loaded in a free block of the upper memory area (UMA). This requires EMM386.EXE or a similar expanded memory driver loaded.

The Software

But how did I create my new font? Well, initially I used FONTEDIT.COM. Unfortunately, this program can generate .COM files without TSR abilities. Or I don't know how to make TSRs. Another issue is that the executable program is around 8 Kb. Then, while searching the Internet, I found an interesting new program called Fontraption, programmed by a guy called VileR. He did such a great job that I liked his program from the very first moment I loaded it.

Unfortunately, Fontraption looks a little bit weird as rendered by my Tseng Labs ET4000/W32i VGA card. I'm not sure why, but it would've been great if it was rendered perfectly. Anyway, the font editing section looks great.

Apparently, VileR had a lot of fun programming Fontraption. He even included palette manipulation techniques so that he added color combinations unavailable by default on a VGA card. To me, this theme brings back memories. It was 1997 or so, and I was working on this 80286 PC connected to a Tandon amber-monochrome CRT monitor. It looked very similar to a gas plasma discharge display. Which in turn is similar to VileR's Plasmatics palette.

Later Edit: VileR has found a fix for the bug and provided me with a new version of Fontraption. This one works like a charm, correctly loading the fonts from the VGA ROM. The fix was simple, but the underlying root cause is quite interesting. In his own words, VileR says:

[...] when asking the video BIOS to load built-in fonts, BL specifies the target block in map 2 of VGA RAM (0 to 7), and for the 8 x 16 font I accidentally had BL=8. Invalid, but works with most BIOSes since they seem to AND this value with 7. The Tseng one doesn't, so the font ended up in never-land, and the program got garbage when reading from the expected block (0) [...]

Now I am thinking what were the other BIOS programmers trying to overcome with that weird AND operation on the lower part of BX register. There must've been something but the answer is unlikely to be revealed anytime soon.

Enough talk. Let's move on, then.

Thus, I began designing the font of my dreams. Some might find it beautiful, some might find it ugly. But I love it. It is the first iteration of the font, and I'm happy with it. There is still a lot of work to be done, but I did a lot of work on these fonts and I find them usable for now. The base font for my design was the original one that I recovered from the ET4000/W32i ROM. Then I tried hard to remember what the old fonts looked like. I also drew inspiration from the ATI VGA Wonder 16 ROM font.

I exported the font as an executable TSR program and I happily used it for about one year. A few days ago, while working on my ROM BIOS implementation for the ISA I/O Interface, I thought about actually updating the real VGA BIOS code to include my own font. While it might sound crazy and dangerous, I can do it. For this purpose, I exported my raw font to a binary file via Fontraption [^S]ave... F2 command. Great, the existence of Fontraption actually spared me of programming my own ROM font extraction and manipulation tool.

So I started analyzing the Tseng Labs VGA ROM BIOS. For that, I needed a ROM dump. Some time ago, I wrote a small utility program which can read ROM contents. I uploaded the source code and binary files on GitHub.

Originally, I designed this program for use with 28C64B EEPROMs on my ISA I/O Interface. But the only thing that makes any difference is the SDP write protection code. And this is used only for EEPROM writing purposes. In reality, the program can read any ROM located within the PC memory map, provided that you know the mapping address and the size does not exceed 32768 bytes.

GitHub Repository: https://github.com/agroza/eepromrw
Main Program: eepromrw.pas

The command that I used to get the VGA ROM BIOS is:
eepromrw.exe -read -addr=C000:0000 -size=8000 -file=vgarom.bin

It reads 32768 bytes (8000 in hexadecimal notation) from the address designated by segment C000, offset 0000 into the VGAROM.BIN binary file.

Then I wrote another quick and dirty tool that scans the VGAROM.BIN file for the starting location of the 8 x 16 ROM font. Well, in the Tseng Labs VGA ROM, the 8 x 16 ROM font starts at offset 17948 (461C in hexadecimal notation). I don't know at this moment whether this is a standardized offset for the 8 x 16 ROM font or not. But honestly, I don't care that much for now. My goal is to replace the original ROM font with my own.

OK then, time to program another tool that replaces the existing font with the new one. So I wrote ROM Font Replacer. I'm not putting this on GitHub for now as it looks pretty ugly with a lot of hard-coded constants. It would not pass my code quality standards, so I'll be working on it some more before I upload the code. In the meantime, I polished the code and reached an acceptable version which I had already uploaded on GitHub.

GitHub Repository: https://github.com/agroza/romfontr
Main Program: romfontr.pas

The command that I used to embed the new font within the VGA ROM BIOS is:
romfontr.exe -offset=461C -romfile=vgarom.bin -fontfile=ag868x16.bin

It writes 4096 bytes (1000 in hexadecimal notation) of font data from AG868X16.BIN binary file at the given offset 17948 (461C in hexadecimal notation) within the VGAROM.BIN binary file.

I did similar operations for all font sizes and all offsets at which these fonts can be found, as such:

  • [12015 (2EEF)] 8 x 14 font data of 3584 bytes
  • [15900 (3E1C)] 8 x 8 font data of 2048 bytes
  • [17948 (461C)] 8 x 16 font data of 4096 bytes

All good for now, but there is still one more catch. VGA ROM BIOS is an option ROM. And these have checksums. If the System BIOS does not find a valid checksum at the end of the ROM, then it will refuse to initialize it. Thus, no video output, even though the VGA BIOS code is intact and the 8 x 16 fonts exist.

Time to write another program... Oh wait, I already have one that does 8-bit ROM checksums. I wrote it for Windows, but it's OK since I am using Windows to program chips anyway. I have uploaded this program to GitHub already.

GitHub Repository: https://github.com/agroza/romcksum
Main Program: romcksum.dpr

The command that I used to calculate and update the VGA ROM BIOS is:
romcksum.exe -o -vgarom.bin

It performs the 8-bit checksum of all ROM data and updates the last byte accordingly. Furthermore, the optional -O switch instructs the program to validate the file as an option ROM.

Later Edit: I added checksum calculation and updating features directly within the ROM Font Replacer program.

This means that the new command that I could use to embed the new font within the VGA ROM BIOS and calculate and update the 8-bit checksum is:
romfontr.exe -u -romfile=vgarom.bin -fontfile=ag868x16.bin

This feature speeds things up and allows me to skip the intermediary step of using the ROM Checksum Calculator program.

Now I have a Tseng Labs ET4000/W32i ROM BIOS file with my own beloved font as 8 x 16 default for all text modes. That's about it for the software part. Now let's move on to the hardware part.

VGA ROM BIOS Reverse Engineering

But first, let's do some reverse engineering. Why? Because if the card is set to Mode 03h, then it auto-magically replaces a few selected glyphs with some custom ones which are located after the 4096 bytes of 8 x 16 font data. I'm not sure what the reason is behind this approach, but it appears to be interesting, for sure. Strange thing is that if I switch the card to mode 11h or mode 12h, the 8 x 16 font is used correctly, and no glyphs are replaced.

The mystery was quickly unveiled by VileR. I started a conversation with him about the Fontraption rendering issue and I brought the weird glyphs into discussion. He told me that these are alternate font glyphs for the 9 x 16 modes. I knew about these back in the 1990s, but I had no idea where and how they are stored in the ROM. Apparently there are both 9 x 14 and 9 x 16 alternate font tables, located immediately after the standard 8 x 14 and 8 x 16 tables. As a particularity, each glyph data is preceded by a byte that signifies exactly the character ASCII code. Another interesting fact that was revealed after my reverse engineering is that these alternate font tables are terminated by a single null byte.

So I designed wider fonts for the 9 x 14 and 9 x 16 fonts and then wrote another program that isolates the specific wider glyphs from the font data array and writes them to separate files in the format expected by the VGA BIOS ROM rendering routines. Then I merged these files with the modified VGA ROM BIOS and recalculated the checksum byte.

The structure of the whole VGA ROM font data area of my Tseng Labs ET4000/W32i video card is:

  • [12015 (2EEF)] 8 x 14 font data of 3584 bytes
  • [15599 (3CEF)] 9 x 14 alternate font data (19 glyphs) of 300 bytes
  • [15899 (3E1B)] single null (0) byte
  • [15900 (3E1C)] 8 x 8 font data of 2048 bytes
  • [17948 (461C)] 8 x 16 font data of 4096 bytes
  • [22044 (561C)] 8 x 16 alternate font data (18 glyphs) of 323 bytes
  • [22367 (575F)] single null (0) byte

for a total of 10353 bytes of VGA ROM FONT data.

I ended up modifying both MS-DOS batch files that I was using for test purposes, so that they now write all font data in sequence to the VGAROM.BIN file. I am putting here the executable content of the file that also calculates and updates the 8-bit checksum.

romfontr.exe -u -offset=2EEF -romfile=vga.bin -fontfile=ag868x14.bin
romfontr.exe -u -offset=3CEF -romfile=vga.bin -fontfile=ag869x14.bin
romfontr.exe -u -offset=3E1C -romfile=vga.bin -fontfile=ag868x8.bin
romfontr.exe -u -offset=461C -romfile=vga.bin -fontfile=ag868x16.bin
romfontr.exe -u -offset=561C -romfile=vga.bin -fontfile=ag869x16.bin

Now I have got a complete VGA ROM BIOS file with all my new fonts and their alternate representations.

The Hardware

This is my Micro-Labs Tseng Labs ET4000/W32i ISA card. I find it very beautifully laid out. I remember I asked Ted what CAD software he used back then but, I don't remember his answer. It would've been fun to document that as well for historical reasons. The video card uses an unknown type of EPROM. Unknown because it has a beautiful purple label saying Made in America which I don't want to remove or deteriorate in any way. Thus, I don't have any means to know the type of EPROM. But on the PCB, the silkscreen says it is 27C256. Well, I could've sworn it was 27C256 (or compatible) since most, if not all VGA cards use 32 Kbit ROMs anyway.

But let's examine the video card more carefully for now. The ROM socket is one of the cheapest ones ever. Since it was made in America, I would've expected Micro Labs to use Mill-Max or something similar. But I think they went on a cost reduction policy as any other hardware company back then. Under the socket there is this silkscreen text saying PCB MADE IN HONG KONG. Huh! U.S.A. had (and still has) excellent PCB production services. But these come at a price tag that is reflected in the end product. After all the buyer is the one who pays the fabrication costs. The PCB is of good quality. Not better, nor worse than most of the early 1990s computer grade PCBs. But it doesn't compare with the quality of the PCB on my ATI VGA Wonder 16 card.

The card clocks are built around the CHRONTEL CH9294 dual PLL graphics clock generator integrated circuit. These are still available on various sites. The RAMDAC is an AT&T ATT20C490-80 part. These are also available on-line. The ET4000/W32i chip is also available on-line. Which makes me think: what if I'd build my own VGA card? I still have the Tseng Labs datasheets catalog and this VGA controller along with a sample schematic is described in depth. I could improve that design by using modern memory which would be cheaper and easier to source. But this is another topic. For the moment, it is only food for thought. (2024-edit) Isn't it?

The memory is composed of 16 individual integrated circuits of type NN51425P made by NPNX Japan. Honestly, I never heard of this company or these memory ICs up until now. Mine has one mismatched IC. U12 is rated 50 ns instead of 45 ns.

Now I am going to replace the VGA ROM BIOS IC socket. This operation is not for the faint of heart types out there. But I did it before on various other computer grade PCBs. I am going to use a quality Mill-Max augat-class socket. This way, it would be easier to experiment with various VGA ROM BIOS ICs.

Like that.

New socket is in position.

Solder side looks good after the surgery. This video card looks like it just went out of the Factory gates.

Now I am going to program an UV erasable EPROM chip of type 27C256-15 made by Texas Instruments. I am using my TL866II Plus Universal Programmer, which I started to love. I had my share of doubts when I bought it a few months ago, but I'm very happy now. The only issue now is how to erase the EPROM. I don't have an UV-C lamp around. But I can improvise one by breaking the glass of a 250 W mercury vapor light bulb.

ROM IC versus replacement UV erasable EPROM IC.

This 250 W mercury tube burner is a big source of UV-C radiation. As I don't have any 250 W magnetic ballast around, I am using three standard Wolfram filament light bulbs (two 75 W and one 100 W) in series with the mercury burner as a crude form of adaptive AC ballast.

Needless to say:

  • Never look into the UV-C radiation source. It causes permanent blindness!
  • And breaking the glass envelope is dangerous anyway. Mercury vapors are very harmful to the lungs.
  • Then again, operating a broken, internals exposed mercury lamp heater presents electric shock risks that puts life in grave danger.

I know how to do it safely because I've done it before. I am not going to step into any other details for now. One important thing to mention. I am operating this improvised rig outside of the house. The UV-C radiation ionizes the air around and produces ozone. Next, I am positioning the UV erasable EPROM circuit under the mercury burner with the power to the installation turned off. Then I remotely turn on the power to the installation while I am a few meters away. There is always the risk that the mercury burner tube might explode. I count around 5 minutes and then turned the power to the installation off. Then I test the EPROM for all FFs. If the EPROM is not yet erased, then I let it one more minute then check back on it. I repeat these 1-minute cycles until the IC is completely erased. My success rate correlates to around 7-8 minutes of erasing time.

Bonus: nighttime burning of bits and bytes. I got carried by enthusiasm and erased some other EPROMs that I had around, getting them ready for the new microcode. All pictures involving the UV-C radiation source were taken remotely using the auto function of the camera.

The mercury gas discharge lamp glow reminds me of old power rectifier vacuum tubes.

OK, the EPROM is cleared at the moment. All bits are set to 1 (another way to say that all bytes are now FF in hexadecimal notation). The IC has been programmed with the updated ROM file. The precision socket is in position. The EPROM IC fits like a glove.

Time to test the VGA card. Here are the results. I mostly spend my time on Dos Navigator and the Pascal IDE. Thus, it's only natural that I like what the PC renders on the screen.

I forgot the circus of photographing CRT screens... It's very hard not to catch the electron beam scan line somewhere in the middle of the screen.

I'm good for now. No more font resets after starting HWiNFO. And I like what the screen shows me. So I think it's time to put an end to this essay.

Hope you found it interesting.

Your Help Matters

This essay is provided as-is and is not for commercial purposes. It reflects my experiments and research and should be treated as such. I release my work to the public for educational purposes. I did all this at my own expense and in my free time. So if you like my work, or find it useful or inspiring for your projects, please consider making a donation.

Copyright © 2004- Alexandru Groza
All rights reserved.
VER. 1.0 | REV. A