Adding a hard drive to a PC was a reasonably standard upgrade even in the 80s. And in today’s world of retro-computing, we have the XT-IDE card, which adds proper IDE support to old PCs. Which also allows you to use more modern storage, such as Compact Flash cards and Disk-on-Module (DOM) devices.
Before getting into the actual topic of today, the jr-IDE, I want to clear up some confusion regarding IDE first. There are three basic things you need to know about IDE:
- IDE stands for Integrated Drive Electronics. This means that, unlike early hard disk systems, the actual controller logic is integrated on the drive itself. The IDE ‘controller’ on the PC side is little more than an interface (very similar to Roland’s ISA card and MPU-401 MIDI solution).
- IDE was first introduced in 1986, for AT-class machines, and is more or less a direct connection of the ISA bus to the integrated controller on the drive. As such, alternative names are AT-BUS or ATA (AT Attachment). With the introduction of Serial ATA, classic IDE became known as Parallel ATA.
- IDE is a 16-bit protocol, which made it incompatible with PC/XT-class machines, as they only had an 8-bit ISA bus.
In the early days of IDE, PC/XT-class machines were still relevant, and as such, there was a short-lived XT-compatible variant of IDE, which goes by the name XTA or (confusingly) XT-IDE. It was flawed because it used the same approach as regular IDE: a direct bridge between the ISA bus and the drive controller. As the ISA bus was only 8-bit in this case, the integrated controller on the drive had to be specifically compatible with this 8-bit IDE variant. Only a handful of such drives were ever made.
The new XT-IDE
Back in the day, there were a handful of 8-bit IDE controllers available that DID work with 16-bit drives (such as the ADP50). After all, 2×8 bit is also 16-bit. So if you implement a small buffer on the controller, which buffers the 8-bit ISA bus reads and writes and converts them to a single 16-bit IDE bus read or write, you can make any 16-bit IDE drive work on an 8-bit XT bus. From there, all you need is a custom BIOS that implements the required int 13h disk routines that properly interface with this simple buffered interface.
These controllers were rare however, so they are difficult to get hold of for retrocomputing. And this is a problem that the XT-IDE aimed to solve: some retrocomputing enthusiasts developed their own modern IDE controller specifically for 8-bit PC clones. It is a cheap and simple design, which is open source, and you can buy them in kit-form or pre-assembled from a variety of places on the web. And the XT-IDE universal BIOS is also freely available. It even supports DMA transfers.
Yeah yeah, get to the jr-IDE already
This rather elaborate introduction was required to have a good idea of what an XT-IDE is, and why you want one in your vintage 8 bit DOS-machine. And well, the PCjr is an 8-bit DOS-machine. Since it has no ISA slots, you cannot use the XT-IDE as-is. However, it has a ‘sidecar’ expansion bus on the side of the machine, which is similar to an ISA slot. There are adapters available that allow you to use an ISA card in the sidecar slot:
There are some limitations (not all IRQs are available on PCjr, there is no DMA, and BIOS ROMs may or may not work depending on how compatible they are with the PCjr environment), but you can at least get certain ISA cards working on a PCjr with this contraption, including some hard disk controllers.
And that’s interesting. Namely, since the PCjr failed in the marketplace, hard disk interfaces are extremely rare for the PCjr, and to my knowledge, no IDE interface existed, only SCSI or MFM. Which will be different to interface with more modern drives. So, some PCjr fanatics tried to get the XT-IDE working on the PCjr. Did it work? Not initially, but with some massaging of the BIOS, they could get it running.
The obvious next step would be to not use an ISA card with modified BIOS in an ISA-adapter for the PCjr, but to design a new PCB that would plug into the PCjr’s sidecar slot directly, which would no longer make it an XT-IDE, but rather a jr-IDE. Somewhere around this point, Alan Hightower of retrotronics.org joined the project. He would design the final PCB that became the jr-IDE as we know it today.
This project quickly got out of hand though (in a good way), as people were thinking: “If we’re going to make a new sidecar for PCjr anyway, why not add all sorts of other useful features as well?” This resulted in the following:
- The IDE interface (including phantom power on pin 20, to power Disk-On-Module devices directly)
- 512k of flash ROM BIOS that is fully PCjr-compatible, which can contain the required firmware for the IDE controller, as well as other things you would like to add
- A fully PCjr-compatible BIOS image that can boot directly from hard drives
- 1 MB of static RAM
- Battery-powered real-time clock
- Power On Self-Test (POST) display
See the official retronics jr-IDE page for more background information on the design and features.
I think items 4, 5 and 6 may require some explanation…
128k ought to be enough for anyone
In the category of “Things Bill Gates never said”, we have the memory limit of the PCjr. This is at 128k, rather than the common 640k of the regular PC. Or well, technically it is at 112k, give or take. I already made a short mention of it in an earlier article:
This limitation is a result of IBM sharing the system memory between the CPU and the graphics adapter. IBM designed it so that the memory is divided into ‘page’ of 16k each (by default, it will use 16k of system memory and mirror it to segment B800h, to be compatible with the CGA standard, which has 16k of video memory there, which means there’s only 112k left to DOS from the 128k, not a whole lot). With a maximum of 128k internal memory, you can select from a total of 8 pages. Although it is possible to add extra memory to the machine via a sidecar, it is not possible to address the extra memory as video pages. So the video memory always has to be in the first 128k of memory (this is a limitation that was overcome in Tandy 1000 models, which put memory expansions before onboard memory, effectively moving the onboard memory, including video RAM up, so the video RAM was always in the last 128k of the total system memory, instead of the first 128k on the PCjr. Some models even allowed you to add extra memory beyond 640k, which was only used for video).
So, what does it matter where your video memory is exactly? Well, in theory it doesn’t, if you are running PCjr-specific software, for example from a cartridge, of self-booting software, which are aware of the video memory being somewhere in the first 128k. But if you use DOS, there is a problem: DOS does not understand the PCjr memory layout.
DOS was designed with the assumption that system memory is a single contiguous area of memory, starting from address 0, and going up to a limit that is reported by the system BIOS. This assumption does not hold for the PCjr. So what can you do? Well, the workaround is as beautiful as it is kludgy: you write a dummy device driver, which allocates all the memory up to 128k. This driver is loaded at boot time, so DOS will consider all memory below 128k in use, and once DOS is booted, it will load any application into the extended memory beyond 128k. This means that it won’t interfere with the video memory.
The downside is of course that you are wasting memory below 128k, which is neither used by DOS nor by video. Since the device driver ‘owns’ the memory, it can repurpose it for other uses. So a common use is to make a small RAM disk out of it, so you can store small files in-memory.
This article also explains it nicely with some diagrams. The most popular driver that allows you to make use of PCjr memory expansions under DOS is JRCONFIG.SYS, originally written by Larry Newcomb.
Fun fact: because static RAM is used, no memory refresh is required. As you may know, the original IBM PC uses a combination of the PIT and the DMA controller to periodically (once every 72 IO cycles) read a single byte, which effectively refreshes the system memory. The PCjr has no DMA controller. It does not need to refresh its memory explicitly, as it is shared with the video controller, which periodically reads from memory anyway (once every 4 IO cycles), to display the image.
So where a stock 64k or 128k PCjr is slower than a PC because the video controller inserts more wait states on the bus than the DMA refresh does… with a static RAM expansion it is actually the opposite! Since the static RAM is not used as video memory, and does not require a refresh either, there are NO wait states. This means that the PCjr actually runs slightly FASTER than a PC now. Also, where 112k (or even 96k if you want to use the fancy PCjr modes that require 32k of VRAM) is very cramped for any kind of DOS application, you can now have over 600k available for DOS, similar to a regular 640k PC configuration.
Because, wait a second, there’s 1 MB of static RAM on the card? Yes, well, similar cards also exist for the IBM PC. And you cannot necessarily use everything. However, on the PC you CAN use upper memory blocks (UMBs) above the 640k range. It’s just that the memory directly above 640k is reserved for EGA or VGA adapters (segment A000h). So DOS itself will not normally go beyond 640k, and UMBs are a hack to load small device drivers in parts of the range above 640k that is not already mapped to a hardware device.
On a PCjr however, you have a fixed onboard video controller. And it is basically an extended CGA controller, which maps its memory at B800h. So there is no reason why you can’t just push memory up to that limit, which is 736k. This would make up for the ‘lost’ memory below 128k where the video buffers are mapped. JRCONFIG.SYS will do this for you, giving you well over 600k of free conventional memory in DOS. So, with the jr-IDE you not only get FASTER memory than on a regular IBM PC, you get MORE memory as well.
What time is it?
As you may know, the IBM PC/AT introduced a standardized battery-powered clock as part of the MC146818 CMOS chip. But what happened before that? In the early days, computers had no absolute time source at all. DOS used timestamps for its files, so a proper real-time date and time were required. It did this by prompting the user to enter the correct date and time at every boot. Then DOS would use the PIT at 18.2 Hz to periodically update this internal time (this also meant that if you reprogrammed the PIT for your own software, and didn’t call the original handler periodically, the time would not be updated. So running certain software would mess up the time keeping of DOS).
Technically this never changed, once the AT was introduced. The only difference is: when DOS detected an AT, it knew there would be an MC146818 or compatible chip with a real-time clock (RTC) available. And it could just read the correct date and time at startup, rather than having the user enter them manually. The actual time keeping during the DOS session was still done via the PIT at 18.2 Hz.
But for PC/XT-class machines, there were also third-party addons for a battery-powered RTC. And many PC/XT-class clones would integrate a battery-powered RTC on the motherboard. They basically worked the same, except you had to load a non-standard driver from CONFIG.SYS or run a command line utility from AUTOEXEC.BAT to get the date and time from the RTC into DOS at every boot.
And this is what the jr-IDE does as well. It adds a Dallas DS12887 chip, which is a clone of the MC146818. So it is actually register-compatible with an AT. The only difference is the timer interrupt, as the PCjr has only one PIC, where the AT connects it to the second PIC. The sidecar interface only supplies three interrupt lines (IRQ1, IRQ2 and IRQ7). So you can configure the jr-IDE to select one of these, or disable it if you want to keep these scarce resources available for other devices. And it supplies a simple utility to load the date/time at bootup. There we are, you never have to manually enter the date and time again, at every boot.
POST cards from the edge
Power-On Self Test. You are probably familiar with that. Every PC-like machine will first do a self-test when it is powered on, before it will try booting from a disk. The most visible part of that is usually the memory self-test, which shows a counter of how much memory has been detected/tested. This POST is part of the BIOS.
But what you might not know, unless you have been hacking around with BIOS code before, is that as early on as the IBM 5160 PC/XTs, many BIOSes had a simple debugging mechanism built in. The BIOS would write a status byte to a designated port at different parts of its self-test, as a primitive progress indicator.
If you have problems with booting such a machine, you can install a so-called POST-card into the machine, which is a simple ISA card with a two-digit display, which allows you to see the codes as the BIOS is performing its tests.
The jr-IDE also integrates such a POST display on its board, and makes it available through port 10h, which is what the PCjr BIOS uses. This can be a very useful debugging tool when you want to play around with your own low-level/BIOS code.
But does it perform?
There is more than one way to skin a cat. And the same goes for implementing a hard disk interface. On an x86 CPU, you have two ways of interfacing with external devices. You can either map the registers (or onboard storage) of an external device into the memory address space of the CPU, as most systems do. Or, a somewhat quirky characteristic of the x86: you can map the registers into the IO address space of the CPU (‘port-mapped IO‘).
The IO address space of the x86 seems to be a leftover from its earlier 808x predecessors: when you have limited address space, having separate IO space can prevent you from having to sacrifice precious memory address space for device IO. This made sense for the 8080 and 8085, as they only had 16-bit address space. For the 8086 however, it made considerably less sense, as it had a 20-bit address space. It’s also somewhat archaic and cumbersome to use, as you only have the special in and out instructions, which have the DX register hardwired as the IO address, and the AL or AX register hardwired as the operand. This makes them far less flexible than using memory addressing, which has various addressing modes, and memory operands can be used by many instructions directly. The in/out instructions are also slightly slower than a regular memory access. Nevertheless, the CPU supported port-mapped IO, and most of the PC was designed around port-mapped devices, rather than memory-mapped ones.
The original XT-IDE was also designed with port-mapped registers. The IDE standard uses 8 registers, which were mapped on an IO-range 1:1. The problem here is that the IDE interface uses a 16-bit register to transfer data, and the IO registers are 8-bit. So in order to implement the ‘missing’ 8 bits, a latch was added on the card, and placed at the end of the IO registers. This meant that the two 8-bit parts of the data register were not in consecutive IO-ports, which means it is not possible to do a more efficient 16-bit in or out operation (which is more efficient even on an 8-bit bus, as there is less overhead for fetching and decoding instructions).
User Chuck(G) then suggested a small modification to the PCB, which swaps some address lines around, so you do get the two data registers side-by-side, and in the correct order. Combine this with an updated BIOS that supports the new addressing, and you got a 2x to 3x speedup.
From this point onward, the paths of the XT-IDE and jr-IDE split. On a regular ISA-based machine, there is a DMA controller available, and DMA transfer is the fastest option, at least, on low-end devices (on faster machines, the DMA controller will be a bottleneck, as it always runs at ~1 MHz. This is enough to saturate the memory of the original PC, at about 1 MB/s in theory, but no more than that). This is because DMA transfers do not require any CPU intervention, so all cycles are spent transferring data, rather than fetching and decoding instructions. James Pearce of lo-tech presented the XT-CFv3, a modified PCB design and matching BIOS, which had DMA capability. It can reach speeds of over 500 KB/s, which is pushing the limits of the machine.
Since the jr-IDE has no DMA controller, and there is no way to even add one via the sidecar interface, as the required lines are missing, a different path was followed: memory-mapping. Instead of making the data register appear only once in the IO-space, a region of 512 bytes is mapped. This is the size of a single sector. This means that you can read or write consecutive bytes on the device by just using REP MOVSW, making things very elegant (as memory-mapped IO does). This is almost as good as DMA, as the instruction needs to be fetched and decoded only once. The looping is done inside the CPU’s microcode. The result is that even on the relatively slow PCjr, you can get over 330 KB/s in transfers. That is faster than any of the port-IO-based XT-IDE implementations. So very impressive indeed. It is a modification that could be backported to the XT-IDE design, but I have not heard of anyone doing this.
So I’m very happy with the jr-IDE I got. The extra memory and the HDD support make it much easier to develop on the PCjr. And I mean that literally: I will use it for development only. I still want to develop software that runs on a stock 128k (or perhaps sometimes even 64k) PCjr. But during development, the extra memory and storage make the process a lot nicer. All in all, it’s a very impressive and useful product, and great work from all the people involved.
Some other resources that may be helpful are Mike Brutman’s PCjr pages. He has a special page on the jr-IDE. On his downloads page, you can find tools such as the aforementioned JRCONFIG.SYS to make use of memory expansions under DOS.
And on the XT-IDE itself, you can find more info on the minuszerodegrees.net XT-IDE page, which contains a large collection of information on the development of the XT-IDE cards, its various revisions, the BIOSes, quirks, bugs and more.