Close

ISA PnP, now that's a hack!

A project log for today's assorted project ramble "grab-bag"

Assorted project-ideas/brainstorms/achievements, etc. Likely to contain thoughts that'd be better-organized into other project-pages

eric-hertzEric Hertz 11/06/2019 at 16:336 Comments

Meh... wrote this a while-back, realized I got some details wrong, intended to fix 'em, but ah well. The jist's there.

-----

Always been a running-background-thought in the ol' noggin... how can ISA plug-and-play function on a bus which, by-design, requires each device to have a dedicated address?

A bus-transaction, simplified, consists of:

1) output the device-address

2) set-up the data-bus

   (Hi-Z for read, or data to write)

3) strobe the /ReadData or /WriteData pin

Note that the order may vary, slightly, but is important! E.G. once that /WD signal comes through, the data and address *must* already be set-up, and remain for a while thereafter, otherwise you may write the wrong data and/or write the right data at the wrong address[es!]. Also note, there's no "non-address", every address, including 0x0000 and 0xffff [which may result from e.g. *not* explicitly setting an address, which can't actually be done], may have a device or memory attached.

Challenges:

A) Bus accesses are handled via hardware, with a very specific protocol. So, no bit-banging of certain pins, even if, in a typical access, that pin is only paid attention to while another is active. 

B) Similarly, pnp devices should work in [older] systems which are not designed for it [the OS will configure the cards]. So, e.g. no turning output-only pins [like /RD, or Address bits] into inputs, or input-only pins like interrupts into outputs, etc. because older hardware just wasn't designed to do that.

C) There are some other signals, e.g. to allow the processor to release the bus to other "co-processors" such as an FPU or DMA controller. I suppose it might've been plausible to do pin-repurposing by e.g. a slight modification/upgrade to one of these, or even, e.g. releasing the bus to a new device [like an ISA card designed as a PnP-"host"], but, realistically, by the time PnP was becoming a thing, FPUs and DMA controllers were long-since embedded in the CPU and bridge chip. Further, the I/O logic buffers [or, more importantly, input-only or output-only logic buffers] for each pin on the ISA bus would've been in the bridge-chip on newer systems [or dedicated discrete logic on e.g. a PC/XT], between the FPU/DMA/CPU and ISA bus. So, again, changing the direction of a bus-buffer pin which was designed to be one-way [e.g. /RD, or INT] would not be possible even when the CPU releases the bus. So a theoretical "PnP-host" add-on card still wouldn't be able to e.g. turn /RD at the bridge into an input, nor, maybe, even Hi-Z. Thus, it'd still be driven by the bridge, even while the hypothetical PnP-host card attempts to do the same even, again, if the CPU were to release its control of the bus.

So, basically what I'm getting at is that the only way to access an ISA card is via a well-defined protocol which basically precludes any sort of pin-repurposing, bit-banging, etc.

[I'm sure there are more challenges, but I'm on a roll]

So, then, how can one configure a PnP device whose address has yet to be configured? How do you tell it you're talking to it?

Sure, it could just *listen* to every transaction, to/from every address, but how can it know [how/when to] respond or act upon whatever it "hears"?

And, further, how could this work in a system with *several* such devices. How can one be configured differently from the next? They don't even have the ability to respond, certainly can't talk directly to each other, and the system doesn't even know they're there!

And, further-still, in a system with *several more* non-PnP [nor even PnP-aware] devices which could literally be located at *any* address, and no defined protocol for identifying themselves, how are we to avoid conflict *during* configuration?

So, then, one might think "well, obviously, the first step is to at least get their attention," and that means some sort of signal sent via normal ISA bus transaction... and... whatever signal that may be, it can't cause havoc with other devices... 

And, basically, as simplistic as it could be, they decided on a single common address for all PnP cards' configuration-registers. [Listen-only, so-far].

How'd they get away with *not* interfering with other non-PnP devices that might use that address? 

[And, remember, the world of PC-compatibles is *much* larger and *much* more diverse than a mere home/office/gaming-rig... we're talking research and industry, CNC machines, etc. many with *very* custom ISA cards, maybe even one-of-a-kind. That company's heating system could exist at that same address!]

So how do they guarantee not interfering with heating systems? They don't. Simply. 

They chose an address which happens to usually be used for another--at that point in time long-defined--purpose... Then set up a PnP-configuration protocol that, should that other non-PnP device exist [which it usually does], won't cause trouble with that particular device at that particular [conflicting] address.

So, they chose to use the parallel-port's status-register address for ISA-PnP configuration. Again, that means: every ISA-PnP card *and* the parallel port share the same address, initially/at-boot. And, here, by "share," I don't mean somehow each bus-transaction gets somehow distributed to the appropriate device. I mean that *all* these devices receive and process *all* transactions at that shared address.

This works-ish because *usually* A) the only non-PnP devices that *usually* use that address are parallel ports, B) the parallel port status-register is *usually* read-only [so, since wired as-such, a Write-access will have no effect on the parallel port], C) this PnP configuration-register, located on every ISA-PnP device, is *write-only*

... aside ...

Z) [I suppose] even if the parallel-port's status-register is Read/Write--e.g. a newer port design may write the status-register to configure newer modes like ECP--usually the printer/zip-drive/scanner driver is loaded long after ISA-PnP configuration, and thus the random junk left in the parallel-port's status[Read]/configuration[Write] register will most-likely be overwritten with the desired configuration later. 

Again, there's a lot of presumption, here! Here's hoping said drivers don't rely on an expected boot-default configuration and/or use Read/Modify/Write! Or, maybe, the ISA-PnP system loads default values back to the parallel-port's status/configuration register when complete. Though, knowing a tiny bit about ECP, which basically treats the parallel port like a bus [with transaction protocols, like ISA or IDE, rather'n essentially bit-banged like old-school parports], it seems plausible certain random parallel-port configuration settings--set during the PnP-configuration scheme--could initiate transactions with parallel-attached devices, possibly leaving them in weird/unknown states! This is an aside, and I'm betting was probably considered in this choice of address.

But, another consideration goes for custom cards... hacking a parallel-port circuit is relatively easy, consisting mostly of 7400-series latches and buffers. E.G. original parallel cards were unidirectional, the data-pins output-only. Converting one of these cards to bidirectional required little more than cutting and rewiring the trace leading to the data-latch's /OutputEnable pin, thus allowing the data-latch to remove its data from the output pins so they could be driven by the device. [This was made extremely easy because the data pins had a read-back buffer attached already, for things like read-modify-write of the data in the output latch.]  Now, doing a similar modification to the status-register would be nearly as simple. Piggybacking a 74374 latch onto the status-register latch chip would be an easy way to add an additional 8 outputs to the parallel port. In consideration of the amount of circuitry necessary to interface with the ISA bus [address decoders, etc], it seems almost likely such "hacks" would've been somewhat common practice for e.g. one-off industrial/heating/lighting controllers [nevermind hobbiests] where rewriting the software is no longer an option. And, now, upon upgrading to Win95, replacing the motherboard or flashing the BIOS with one that's PnP-aware, or installing an additional [now PnP] serial port, etc. there's a lengthy process during boot, and any time in the device-manager, flipping relays at speeds which could be damaging, and unknown values-written--and unchanged until the custom software is [re]loaded--running motors past limit-switches, and so-forth. I'm betting there were many affected who had no idea what was responsible.

Further, I'm pretty certain there existed some devices which intentionally used the parallel-port's register-interface, and likely extended it a bit [like the hypothetical one-off card described earlier], such as, maybe, GPIB cards with printers attached. So that the typical DOS print routines could be used with a much more sophisticated bus. In such a case, that read-only status-register would be a perfect place to add a configuration-register e.g. for the printer's GPIB address.

Suffice to say, the choice of address for writing the configuration-register seems a bit funky to me. though it may be one of the best-available choices.

[Note, also, the thought crossed my mind to use a *memory* address, rather than I/O; writing random values to an otherwise not-yet-used RAM location should have no effect on anything. There are several potential hurdles, here. A) the configuration process might occur at any time [even after the OS is loaded, as in Win9x's Detect-hardware, or a DOS driver for a PnP card], so finding an always-non-allocated memory address... well, that pretty much does-in that idea. B) in the era of fast RAM, it's entirely likely memory-accesses to actual RAM are intercepted by the bridge-chips, directed to the faster SIMMs and *not* directed to the slower ISA bus [also], as would've always been the case in older systems where every bus transaction was identical. C) cache could make it even more difficult! [Though, I think that can be disabled]. [But, then, it must be a pretty sophisticated routing system, as some memory-locations are explicitly used by the I/O system, such as the VGA frame-buffer... hmmm... is the original 640K *always* limited to ISA speeds?!]

... end aside ...

Anyhow, any write-transaction at that address gets all of the ISA-PnP cards' attentions.

From there, there's a "key" sent to, again, all of the ISA-PnP cards; a specific sequence of bytes sent to that same address. This confirms to the cards [all of them] that the system wants to start configuring them.

But, now, how does it configure *only one* card? [And, actually, "card" is inappropriate, as multi-function cards need multiple configurations].

So we need a bit more background. Yes, each card [or function?] has a unique [UNIQUE] identifier, including a 32-bit manufacturer ID, and a 32-bit unique ID [so, say you have two identical cards, they can be separately-identified].

Alright, but now how you gonna select the first one to configure? Test every single possible ID of the 2million-squared? Nah, booting would take forever.

So, yes, more background; there is an address *also* for read-back. BUT: this one's at a different location. Otherwise, reading-back from the shared parallel-port status-register and PnP configuration-register address *will* get a response from the parallel-port [when installed, which was *usually*], which would cause bus-contention with the PnP cards' also responding.

But Wait! The parallel-ports other registers are all R/W, so we can't use them! And there could be *anything* at *any* address!

So, they've got a *range* of addresses to choose from, for read-back. But, no, there's not yet a way to set a unique read-back address for each PnP device. It gets crazier.

After the "key" unlocks configuration-mode on *all* the devices, it first searches for available devices, and requests their IDs. In that request, it tells the devices which address to respond at.

Again, two problems: there may already be another non-PnP device there, and *all* PnP devices receive the same request-to-identify. Thus, multiple devices *will* all respond simultaneously on the same data bus at the same time. Contention-much?

This is by-design. (Wow!)

So, first, the system can detect whether a non-PnP device responds, because it's expecting responses in a very specific pattern. [More on that later]. If it detects data outside that pattern, then it knows a non-PnP device exists there, then retransmits the "ID request" telling the PnP devices [all of them, still] to respond at a different address. Repeat until an open address is found.

[And, I guess, no worries of damaging buffer-outputs when all the PnP devices drive the data bus at the same time as the non-PnP device?]

OK, now what?

Pattern, contention... right, so, this is as far as I've gotten in-detail, skimming the rest. So take the following with a grain of salt:

The "specific pattern" consists of, essentially, each ID-bit being sent one-at-a-time through the lowest data bit, each ID bit is requested sequentially. That means, for the first request, if bit0 of any card's ID is '1' then they simultaneously output that to the bus. When that's the case, any card whose ID's bit0 is '0' drops-out for the remaining sequence. Thus, the data-bus is driven by *all* ISA-PnP devices whose ID-bit0=1.

Now, I'm pretty sure I read that there's an open-collector scenario in here... not exactly sure how. And, actually, I vaguely recall something about the devices' encoding the ID-bit0 differently [maybe 0b01 for '0' and 0b10 for '1'?] But, again, if the data bus reads anything other than those two expected values, then the system knows there's a non-PnP device there, and starts over at a new address.

Where am I going with this? I wanted to breeze through these details because I wanted to make some point...

Oh yeah, after each ID bit is transmitted, and the lower-IDed devices "drop-out" then the remaining devices respond with 0x55 and 0xAA. I think, first, this identifies that, indeed, even if all cards' ID-bit is '0', that it should continue. This, too, helps to verify that there's not a non-PnP device at the response-address.

Then it does the process, again, for ID-bit1, and so-forth. After all 64 ID bits shift through [and 8 CRC bits], all but one device have "dropped out," and its ID is now known. It drops-out entirely, and the process repeats for the next device, and the next.

OK... now where was I going with all this?

Dunno.

It's a clever technique to add functionality to a bus not originally designed for such a task, the "upgrade" can be done entirely in software by any PC, needn't even require BIOS support. 

Maybe "now that's a hack."

Maybe I'll find a PnP [8-bit?] card to throw at #Improbable AVR -> 8088 substitution for PC/XT 

Discussions

Ken Yap wrote 12/13/2019 at 04:23 point

Oh man that's ancient. I don't have even PCI cards any more, which addressed auto-configuration. So forgive me if TO;DR. Too many bad memories. :)

Also I believe you need BIOS firmware that does PnP, you can tell if the configuration mentions it, so not the original BIOSes.

And you should probably get Dave's Dev Lab to add a link to your explanation.

  Are you sure? yes | no

Eric Hertz wrote 12/13/2019 at 17:41 point

well, see, unlike PCI or PCIe, ISA can be wired very similarly to SRAM, EEPROMs, etc, so adding it to an 8-bit uC is *almost* supported by their memory-bus interface and/or relatively simple to code through GPIOs. ;)

  Are you sure? yes | no

Ken Yap wrote 12/13/2019 at 17:55 point

You should have been around when I pitched all my ISA mobos and cards into recycling.

  Are you sure? yes | no

Eric Hertz wrote 12/13/2019 at 18:03 point

lol, didja know there's a whole website dedicated to folk who love putting junk electronics to new/unintended uses?

  Are you sure? yes | no

Ken Yap wrote 12/13/2019 at 21:07 point

I do that too myself, but that old hardware just takes up too much space and power. So I had to make room for more junk^wspares. Usually I toss out a whole generation of technology at a time, e.g. all ISA stuff, all telephone modems (but I kept the power supplies), all floppies and drives, all valves (there were some gems in there like magic eye tubes), all Ge transistors (somebody wanted to make an amp with the old-time sound).

But whatever floats your boat.

  Are you sure? yes | no

Eric Hertz wrote 12/13/2019 at 18:27 point

For the TL;DR'ers:

By-design, PnP does *not* require a PnP-BIOS. 

It can be implemented in software [drivers/OS] using *any* standard ISA bus, down to that of the IBM PC/XT.

Without hardware/BIOS modification

By Design.

That's *why* I consider it "quite a hack."

  Are you sure? yes | no