2015-11-29

Retrofitting a new EEPROM into an old PC

Recently I had the need to install an option ROM into my newly repaired 286, so that it could boot from IDE devices. That journey wasn't quite as straightforward as I had expected, so I thought I would write down what I'd done in case anyone else has a similar issue one day.

The fine folks at the XTIDE project have produced code suitable for use as an option ROM, which means if you can get it to appear in the PC's address space between C0000 and F0000 then the system BIOS will run the code automatically during the boot process, thus allowing booting from any installed IDE controller cards.

The easy option would have been to purchase a Lo-tech ISA ROM board, which allows a brand new EEPROM-compatible flash chip to appear in the correct address space. However I have many ISA network cards with boot ROM sockets, and since I intend to have a network card in each of these PCs anyway, I could save an expansion slot by putting the XTIDE ROM on the network card instead.

The complication arises as soon as you realise that almost all boot ROM sockets are 28-pin, and almost all 28-pin chips are older style EEPROMs, which require 12V to program and in many cases UV to erase. Since I don't have the hardware for this, my idea of reusing an old 28-pin chip was a dead end. I had previously used a PCI Realtek 8139 to dump 28-pin ROM chips, and this explains why it didn't seem to be capable of writing to them as well.

It turns out that most EEPROMs are standard 32-pin devices, and you can still buy them new for a few dollars each. Looking closely at the datasheets, I thought it might be possible to fit a 32-pin EEPROM into a 28-pin socket, if a few additional connections were made. With this plan in mind, I went ahead and purchased a handful of the same SST39SF020A chips used by the Lo-tech board, as well as some 32-pin EEPROM sockets to base my adapter on.

As it turns out, the adapter is very simple. You only need to connect all the overhanging pins together, and tie them to VCC (pin 28 on the 28-pin version.) One of these pins is the write enable line, so this means it is not possible to flash the chip in a 28-pin socket. It also means if you modify the chip directly, it will no longer be possible to reflash it. By modifying a 32-pin IC socket instead, the chip can be removed and reflashed as needed in a native 32-pin programmer.

This is the pinout of the two chip types:

From here you can see that if we plugged the 32-pin chip into the 28-pin socket, with pins 1-2 and 31-32 overhanging the socket, all the data lines and most of the address lines match up. However VCC would arrive on pin 30 and the real VCC pin would be without power. To build an adapter we will need to at least connect power to the real VCC. Pin 31 also enables write mode when pulled low, so we can tie that to VCC as well to ensure the chip is always in read-mode.

Since pin 30 (where VCC is coming in from the 28-pin socket) is used for A17, and A17 is only needed to access storage capacity larger than 128kB, we can leave that connected to VCC for simplicity. The drawback of doing this is that we will "limit" our storage capacity to 128kB, however this is not really a limit, because the 28-pin socket does not have an A17 line so it can only access a maximum of 128kB anyway.

The A16 and NC (pin 1, used for A18 in 512kB chips) should also be tied to something, so we will use VCC as well since it is close by. If we didn't do this and left the pins unconnected, they will "float" and could change value unexpectedly. This would effectively make the contents of the ROM vanish momentarily, causing the PC to lock up if it happened to be running code from the chip at the time.

EEPROM memory map. Only the upper 128kB will be visible through the 28-pin socket, whatever the chip capacity.
The net effect of all this is that all the upper address lines will always be high, causing only the upper 128kB of flash storage to be accessible. This is important when flashing the chip, as any chip larger than 128kB will need the desired content placed in the highest 128kB. If a 512kB chip is used for example, then data from 0kB to 384kB will be ignored, and only the 128kB window from 384kB to 512kB will be accessible through the 28-pin socket. Anything reading the 28-pin socket will of course be none-the-wiser, and will access the data from 0kB to 128kB as normal.

Connecting all these pins together looks like this: (connections shown in red)

As mentioned previously, making these connections directly to a chip will prevent it from being reflashed, so for maximum flexibility a 32-pin PDIP socket should be modified so the flash chip can be removed as needed. The 32-pin PDIP socket fits nicely into a 28-pin socket, which means the only parts required to construct this adapter are the 32-pin socket itself and some very short lengths of wire.

After making the necessary connections, the adapter should look like this:

This picture is of course looking from the bottom up, so the connections are mirrored compared to the top-down view shown in the earlier diagrams. This adapter mounts nicely in a 28-pin EEPROM socket:

It also doesn't stick out much farther than normal, so it just fits in the available slot space without interfering with the neighbouring slot.

In my case, after having flashed the XTIDE BIOS, the 286 recognised the option ROM on the first attempt and happily ran it during the boot process!

Flashing the chip

To actually flash the chip, I used the fine flashrom tool.

Unfortunately my first attempt was to use a 3Com 3C905 Ethernet card as it was the only one I had with a 32-pin EEPROM socket, however I discovered that this card lacks the A17 address line, restricting its ability to flashing chips that are 128kB or smaller. Since I had a 256kB chip, and the 28-pin adapter requires the content placed in the upper-most address, I couldn't put the XTIDE code in the upper 128kB if the 3Com card could only flash the lower 128kB of the chip!

I then noticed the motherboard I was using - a Gigabyte GA-6BXC - had a 32-pin BIOS chip. Flashrom supports the Intel PIIX4 chipset used by this motherboard, so I could hot-flash the chip using the motherboard's BIOS socket.

I had never hot-flashed a machine before, but the process was very simple. Once Linux had started booting, the motherboard BIOS chip was removed, and the target EEPROM carefully placed in the socket. I didn't push it all the way in, just enough to make contact. Flashrom detected the chip, wrote the content and verified it again without complaint, so I could be sure the content was flashed successfully and the chip was easy to remove again. Since I had to buy the flash chips in a pack of 5, I used the hot-flash process to flash all five chips. One of them was bad - flashrom couldn't recognise it and the chip got very hot very quickly, but the other four were fine (and yes I tried three times and the chip was definitely in the right way.)

Since the XTIDE BIOS is only 8kB (or 12kB for the "large" version), it needs to be padded up to the size of the flash chip - 256kB in my case. I used a simple shell script for this:

$ (for ((I=12288; $I<16384; I=$[$I+1])); do echo -en "\xFF"; done) > pad.bin
$ cat ide_atl.bin pad.bin > xtide-16k.bin
$ cat xtide-16k.bin xtide-16k.bin xtide-16k.bin xtide-16k.bin > xtide-64k.bin
$ cat xtide-64k.bin xtide-64k.bin xtide-64k.bin xtide-64k.bin > xtide-256k.bin

This creates a 256kB file, with the complete XTIDE ROM at every 16kB mark. This means we only need to tell the Ethernet card the boot ROM is 16kB in size, and it won't need to take up a huge amount of memory which could otherwise be used for UMBs. Technically we could have done the calculations to get the XTIDE code to sit at exactly the 128kB mark, but since the rest of the chip is going to be ignored, it doesn't matter if we have duplicate data in there anyway.

I flashed this 256kB file to the chip and placed it in the network card's boot ROM socket, and to my surprise everything worked the first time. You can see in the output of Norton Utilities' SI that there is an option ROM at address C800 (along with the video BIOS at C000 and the system BIOS at F000):

Part of the reason for the early success was because I had already found the configuration program for my network card and enabled the boot ROM socket, which was disabled by default. Finding the program to do this was a bit of a challenge, and I'm considering starting a wiki-like card database to assist with this issue.

In my case (and to help anyone from Google), the card had an EN50903 chipset, with "A.T.C." on it (which stands for Accton Technology Corporation.) It turns out the EN50903 is used on a few cards, but mine was an Accton EN1640. Googling for en1640.zip got me the DOS drivers with the setup program, allowing me to set the port address, IRQ, and enable the boot ROM. Since my VGA BIOS stopped at segment C800, I put the boot ROM there and set it to 16kB. (Side note: it turns out the EN50903 is happy running in 8-bit mode, so this solution should also work for an XT, even though the card has a 16-bit ISA connector.)

Now I can start using IDE devices with my 286!