You Got Something On Your Processor Bus: The Joys Of Hacking ISA And PCI

Although the ability to expand a home computer with more RAM, storage and other features has been around for as long as home computers exist, it wasn’t until the IBM PC that the concept of a fully open and modular computer system became mainstream. Instead of being limited to a system configuration provided by the manufacturer and a few add-ons that really didn’t integrate well, the concept of expansion cards opened up whole industries as well as a big hobbyist market.

The first IBM PC had five 8-bit expansion slots that were connected directly to the 8088 CPU. With the IBM PC/AT these expansion slots became 16-bit courtesy of the 80286 CPU it was built around. These slots  could be used for anything from graphics cards to networking, expanded memory or custom I/O. Though there was no distinct original name for this card edge interface, around the PC/AT era it got referred to as PC bus, as well as AT bus. The name Industry Standard Architecture (ISA) bus is a retronym created by PC clone makers.

With such openness came the ability to relatively easy and cheaply make your own cards for the ISA bus, and the subsequent and equally open PCI bus. To this day this openness allows for a vibrant ecosystem, whether one wishes to build a custom ISA or PCI soundcard, or add USB support to a 1981 IBM PC system.

But what does it take to get started with ISA or PCI expansion cards today?

The Cost of Simplicity

From top to bottom: 8-bit XT bus, 16-bit AT/ISA, 32-bit EISA.

An important thing to note about ISA and the original PC/AT bus is that it isn’t so much a generic bus as it describes devices hanging off an 8088 or 80286 addressing and data bus. This means that for example that originally the bus is as fast as the clock speed of the CPU in question: 4.77 MHz for the original PC bus and 6-8 MHz for the PC/AT. Although 8-bit cards could be used in 16-bit slots most of the time, there was no guarantee that they would work properly.

As PC clone vendors began to introduce faster CPUs in their models, the AT bus ended up being clocked at anywhere from 10 to 16 MHz. Understandably, this led to many existing AT (ISA) bus cards not working properly in those systems. Eventually, the clock for the bus was decoupled from the processor clock by most manufacturers, but despite what the acronym ‘ISA’ suggests, at no point in time was ISA truly standardized.

It was however attempted to standardize a replacement for ISA in the form of Extended ISA (EISA). Created in 1988, this featured a 32-bit bus, running at 8.33 MHz. Although it didn’t take off in consumer PCs, EISA saw some uptake in the server market, especially as a cheaper alternative to IBM’s proprietary Micro Channel architecture (MCA) bus. MCA itself was envisioned by IBM as the replacement of ISA.

Ultimately, ISA survives to this day in mostly industrial equipment and embedded applications (e.g. the LPC bus), while the rest of the industry moved on to PCI and to PCIe much later. Graphics cards saw a few detours in the form of VESA Local Bus (VLB) and Accelerated Graphics Port (AGP), which were specialized interfaces aimed at the needs of GPUs.

Getting started with new old tech

The corollary of this tumultuous history of ISA in particular is that one has to be careful when designing a new ‘ISA expansion card’. For truly wide compatibility, one could design an 8-bit card that can work with a bus speed from anywhere from 4.77 to 20 MHz. Going straight to a 16-bit card would be an option if one has no need to support 8088-based PCs. When designing a PC/104 card, there should be no compatibility issues, as it follows pretty much the most standard form of the ISA bus.

The physical interface is not a problem with either ISA or PCI, as both use edge connectors. These were picked mostly because they were cheap yet reliable, which hasn’t changed today. On the PCB end, no physical connector exists, merely the conductive ‘fingers’ that contact the contacts of the edge connector. One can use a template for this part, to get good alignment with the contacts. Also keep in mind the thickness of the PCB as the card has to make good contact. Here the common 1.6 mm seems to be a good match.

One can easily find resources for ISA and PCI design rules online if one wishes to create the edge connector themselves, such as this excellent overview on the Multi-CB (PCB manufacturer, no affiliation) site. This shows the finger spacing, and the 45 degrees taper on the edge, along with finger thickness  and distance requirements.

Useful for the electrical circuit design part is to know that ISA uses 5 V level signaling, whereas PCI can use 5 V, 3.3 V or both. For the latter, this difference is indicated using the placement of the notch in the PCI slot, as measured from the IO plate: at 56.21 mm for 3.3 V cards and 104.47 mm for 5 V. PCI cards themselves will have either one of these notches, or both if they support both voltages (Universal card).

PCI slots exist in 32-bit and 64-bit versions, of which only the former made a splash in the consumer market. On the flip-side of PCI we find PCI-X: an evolution of PCI, which saw most use in servers in its 64-bit version. PCI-X essentially doubles the maximum frequency of PCI (66 to 133 MHz), while removing 5V signaling support. PCI-X cards will often work in 3.3V PCI slots for this reason, as well as vice-versa. A 64-bit card can fall back to 32-bit mode if it is inserted into a shorter, 32-bit slot, whether PCI or PCI-X.


Driving buses

Every device on a bus adds a load which a signaling device has to overcome. In addition, on a bus with shared lines, it’s important that individual devices can disengage themselves from these shared lines when they are not using them. The standard way to deal with this is to use a tri-state buffer, such as the common 74LS244. Not only does it provide the isolation provided by a standard digital buffer circuit, it can also switch to a Hi-Z (high-impedance) state, in which it is effectively disconnected.

In the case of our ISA card, we need to have something like the 74LS244 or its bi-directional sibling 74LS245 to properly interface with the bus. Each bus signal connection needs to have an appropriate buffer or latch placed on it, which for the ISA bus is covered in detail in this article by Abhishek Dutta. A good example of a modern-day ISA card is the ‘Snark Barker’ SoundBlaster clone.

PCI could conceivably be done in such a discrete manner as well, but most commonly commercial PCI cards used I/O accelerator ASICs, which provide a simple, ISA-like interface to the card’s circuitry. These ICs are however far from cheap today (barring taking a risk with something like the WCH CH365), so a good alternative is to implement the PCI controller in an FPGA. The MCA version of the aforementioned ‘Snark Barker’ (as previously covered by us) uses a CPLD to interface with the MCA bus. Sites like OpenCores feature existing PCI target projects one could use as a starting point.

Chatting with ISA and PCI

After creating a shiny PCB with gold edge contact fingers and soldering some bus buffer ICs or an FPGA onto it, one still has to be able to actually talk the actual ISA or PCI protocol. Fortunately, a lot of resources exist for the ISA protocol, such as this one for ISA. The PCI protocol is, like the PCIe protocol, a ‘trade secret’, and only officially available via the PCI-SIG website for a price. This hasn’t kept copies from the specification to leak over the past decades, however.

It’s definitely possible to use existing ISA and PCI projects as a template or reference for one’s own projects. The aforementioned CPLD/FPGA projects are a way to avoid implementing the protocol oneself and just getting to the good bits. Either way, one has to use the interrupt (IRQ) system for the respective bus (dedicated signal lines, as well as message-based in later PCI versions), with the option to use DMA (DRQn & DACKn on ISA). Covering the intricacies of the ISA and PCI bus would however take a whole article by itself. For those of us who have had ISA cards with toggle switches or (worse), ISA PnP (Plug’n’Pray) inflicted on them, a lot of this should already be familiar, however.

As with any shared bus, the essential protocol when writing or reading involves requesting bus access from the bus master, or triggering the bus arbitration protocol with multiple bus masters in PCI. An expansion card can also be addressed directly using its bus address, as Abhishek Dutta covered in his ISA article, which on Linux involves using kernel routines (sys/io.h) to obtain access permissions before one can send data to a specific IO port on which the card can be addressed. Essentially:

if (ioperm(OUTPUT_PORT, LENGTH+1, 1)) {
if (ioperm(INPUT_PORT, LENGTH+1, 1)) {

outb(data, port);
data = inb(port);

With ISA, the IO address is set in the card, and the address decoder on the address signal lines used to determine a match. Often toggle switches or jumpers were used to allow a specific address, IRQ and DMA line. ISA PnP sought to improve on this process, but effectively caused more trouble. For PCI, PnP is part of the standard: the PCI bus is scanned for devices on boot, and the onboard ROM (BIOS) queried for the card’s needs after which the address and other parameters are set up automatically.

Wrapping up

Obviously, this article has barely even covered the essentials when it comes to developing one’s own custom ISA or PCI expansion cards, but hopefully it has at least given a broad overview of the topic. A lot of what one needs depends on the type of card one wishes to develop, whether it’s a basic 8-bit ISA (PC/XT) card, or a 64-bit PCI-X one.

A lot of the fun with buses such as ISA and PCI, however, is that they are very approachable. Their bus speeds are well within the reach of hobbyist hardware and oscilloscopes in case of debugging/analysis. The use of a slower parallel data bus means that no differential signaling is used which simplifies the routing of traces.

Even though these legacy buses are not playing in the same league as PCIe, their feature set and accessibility means that it can give old systems a new lease on life, even if it is for something as simple as adding Flash-based storage to an original IBM PC.

[Heading image: Snark Barker ISA SoundBlaster clone board. Credit: Tube Time]

28 thoughts on “You Got Something On Your Processor Bus: The Joys Of Hacking ISA And PCI

  1. The Altair 8800 had an open bus, even before there was much to plug in. So did the Apple II, which influenced the “IBM PC”. Other computers generally had an expansion port, less useful if you needed more than one option, but endless boards to fit into them.

    Hobby computers grew big because of third party expansion, and magazines where the boards could be advertised.

    1. S-100 from the Altair didn’t really approach the qualification “mainstream”. The Apple II might have, though figures are hard to come by, it’s something like 6M units for the whole series, less half a million IIcs that didn’t have an exposed bus. This is somewhat hard to compare against IBMs figures, due to them mostly being quoted in dollar sales, so we don’t know if they are top end list prices of $15,000 a pop with expansion cage, extra drives, full memory, representing one unit, or the discount stripped model at more like $3,000 with base level RAM and cassette storage also representing one unit. However, they were reckoned to hit a million units a year 3 years before Apple did on the II series, despite Apple’s headstart. I would guesstimate that all IBM 8 bit bus models, sold in the neighbourhood of 15 million units, that’s PC, XT and all the variations. However, the clone market was reportedly keeping pace with IBM’s output by 1983ish, unlike Apple II clones whose sales were reckoned in the few thousands. Anyway, by end of the 1980s, there would be something like 6 or 7 machines using 8 bit “ISA” for every Apple II bus machine, and 3 or 4 of them for every S-100 based machine.

      1. Except computers became more mainstream with the IBM PC.
        The paragraph after that just seems to dismiss what had come before. It happened before, and was a big part of “home computers” before the IBM PC.

        If the Altair hadn’t had a bus, it likely wouldn’t have gone anywhere, and hobby computers would have stalled. But others could sell boards, easier than a who!e computer, and in turn the variety made the comouters more appea!ing.

        80-Microcomputing got huge, in part from all the third part companies selling things for the TRS-80.

        A lot of things in small computers were big, until another iteration came along to dwarf it.

    1. S100 had even less standardization than ISA. Anyone could use the 100 pin connector and put their computer’s power, data, etc lines wherever they wanted. If you wanted to know if an S100 board should work with your particular computer, you’d need to know if it was a proprietary arrangement or if it copied Altair or SWTPC or some one of the other bigger names in the business.

  2. The problem with listing “firsts” is that it’s so often hard to put your finger on the point where something is different enough from its predecessor to say “here’s where the new thing starts, let’s note the date”.

    But rather than harp on that, I want to mention that, at the home and hobbyist level, PCI marked the transition from “just breaking out the processor pins” to an actual CPU-agnostic bus based on passing messages over the wires. Yes, Macs were doing this with NuBus, itself from Lisp Machines and TI and probably others before, and it was old hat in mainframes, but PCI is where the market traction really started. PCI messages are really simple (“write these bytes” or “I relinquish my control of the bus”). The advantages it gave included (a) not having to reverse the flow of data along the bus as often, which was a big deal, and (b) having signals that didn’t just manipulate memory meant that this “out of band signaling” could be used for all kinds of general-purpose setup. The cost was a *lot* of complexity by the standards of its day, but the payoff was worth it.

  3. I was going to mention the S-100 bus as well which pre-dated the IBM PC as an open standard used by many manufacturers.

    Also in the text the (IBM) PC bus is mentioned then the drawings list the XT bus, for those not old enough to remember the PC and XT bus are the same with the PC bus being 5 slots spaced at 1″ apart and the XT bus being 8 slots spaced at .75″ apart. Most documentation will list as the PC/XT bus naming both.

    The 3/4″ spacing carried over through 16bit ISA, EISA, VLB, etc into the PCI bus today.

    1. This! God i think we (i was early teen back in late80 when my father bought 386) swapped like a dozen of drive ATA cards to make our HDD work (40MB in 1989ish in communist Poland! i think my Dad decided to not buy car just to buy that thing that basically served us to play games). Then the graphics card CGA wouldn’t work there was some strange work around that sort of worked for time so we had to fork out later for VGA, then sound card we bought messed with everything again so did the CD-ROM drive. When we got rid of 386 in 94/95ish for 486 with PCI i was so happy it allowed for so much easier compatibility and changes (not to mention economy was much better my parents finally started earning more and i got old enough for part time job so we could afford better parts)

  4. Back in the DOS days, ISA was fun, you basically could slap any weerdy device down at any unused address, and bang on it directly with IN and OUT. Funky things like 9513 timer chips. Mundane things like 74LS374 for a simple output port.

    Of course, these days you get all of that jammed into one Atmel chip. But it’s not quite the same when you have to develop it over here, flash it over there. On the XT you could light off debug.exe and twiddle your device LIVE in real time.

    1. I hooked up character LCD directly to the raw ISA bus back in the days. The bus timings were close enough. I had to use one of the lower address bits for R/W to meet setup time for the E clock. The LCD code was as simple as I/O reads/writes without the extra GPIO toggling on a microcontroller. Best of all being able to trace C code in the IDE as it runs.

    2. Hmmm, getting me thinking with the all on one Atmel thing, PC/XT supercard with emulated soundblaster, SD card HDD emulator with BIOS and MDA/CGA/EGA emulation bitbanged to a VGA connector. Stick 2 Atmels on it, and could do USB mouse to busmouse/serial mouse… actually maybe scratch that and do ESP8266 handling half of it (4MB room for BIOSes) leverage the wifi on it to appear as internal modem, or NE2000 NIC, and Atmel to pick up the slack.

      I might do that in the (probably not very near) future just to POC the i/o stuffs for a handheld XT clone with an 80c88 I’ve got kicking around.

      1. Probably should look into AVR parts that have External Memory Space as they’ll save a lot of bit-banging to fake a bus. e.g. ATmega64A The external bus cycles looks close enough to the Intel style and can talk to SRAM etc. It even comes with programmable wait states setting.

    3. That is if you where programmer not just user. For users compatibility issues where complete crap. You could change one card and it would mess up with everything and you’d have to try working it out. Fun for teenager me not fun for 40+yo dad who lived in commie country with almost noone to help apart from one IT friend living in other part of the city without car.

    4. There are BASICs, forths, and even MicroPythons for your microcontroller of choice where you can do just that.

      None of them have a full-featured shell, at least when compared to an IDE on your laptop, so most people end up with the write-send-run cycle anyway, which is a shame. But for debugging and tweaking around, having a shell on the microcontroller in which you can run test scripts is gold.

  5. ISA PnP had to wait for the BIOS and operating system support to catch up. The early times were… not great. Windows PnP was quite bad until 98SE.

    The worst was sound card and LPT address conflicts. Windows, especially 95/95a/95B, loved to assign the sound card to the same address as LPT1 – despite jumper or EEPROM settings or the SET line in AUTOEXEC.BAT.

    So I’d have to manually set it in Device Manager to force Windows to see the sound card at the settings it was actually set to.

    Then Windows would change the address. IRQ, and DMA for LPT1 automatically to the same as the sound card. So I’d have to manually force Windows to put LPT1 correctly. Then “magically” it would work. Huzzah. Except in a few cases Windows would re-assert PnP and automatically change the sound card or LPT1 or both back to automatic, and the same conflicting settings.

    IIRC Windows 98 introduced IRQ sharing, but if the BIOS was one that wasn’t up to speed with PnP it still wouldn’t work correctly. I did encounter some computers on which 98 simply would not work.

    Windows 98 Second Edition was when the PnP bugs were all squished. I don’t recall ever having to do any manual forcing of it to stop if from doing stupid things like 95 loved to do with forcing sound cards and LPT1 to conflict. Most PCs that 98 would not work on, 98SE would, including the one I owned at the time. All flavors of 95 had been a PITA to stop it from ignoring the real hardware settings and causing conflicts. 98 would crash during install. 98SE installed without a problem, I installed the drivers and it all worked fine.

    Resource sharing (that finally actually worked) eliminated conflicts.

    1. It was mostly buggy PnP BIOSes that messed things up since they were responsible for enumerating PnP devices. Win98SE probably finally had enough additional workarounds to eliminate the problem for you.

  6. I “hack” the unmentioned microchannel (MCA) bus all the time – for a computer bus, one of the most easy to get information from EVERY possible adapter attached though even ROM BASIC. There is even an easy way for software to determine if the PC has a microchannel bus. A few routines I have done for microchannel are at

  7. This bus was dirt simple to work with and programming at 1,000H

    Got you into the free memory space. I’ve done a couple of designs on it way back when and enjoyed it simplicity. Look up TMS34082 in the back for schematics

  8. Nice article. Bus research and development helps bring system design issues into consideration – Standardization/compatibility/documentation, CPU independence, bus security, PCB form factor, signal integrity, Power-On Reset and Self Test design, asyncrhronous operation, address space,memory mapped i/O vs separate I/O, enabling/disabling adapters, wait states, fetch and deposit vs fly by DMA, Multimastering, , Multiprocessing and caching, low power operation …

Leave a Reply to MinorHavoc Cancel reply

