HGC cards on IBM PCs used to be able to run CGA software by using a CGA emulator. How exactly did those programs work? What were the limitations?
How exactly did those programs work?
They were based on the ability of the Hercules card use the CGA's memory space.
The original MDPA (*1) had (only) 4 KiB of memory mapped at B0000h, while the CGA had 16 KiB of Memory at B8000h. The Hercules card in contrast had 64 KiB of memory (*2), starting at B0000h. To avoid conflicts with a CGA in the same system the upper 32 KiB were by default disabled. By default the Hercules was 100% compatible. In fact, so compatible that the PCs BIOS did recognize and use it as MDA (with 4 KiB Memory). Unlike the MDA, the Hercules card did offer a full graphics mode of 720x348 (*3,4), which occupied 32 KiB Memory, thus offering up to two pages.
CGA emulations used the fact that the second 32 KiB were not only free (when only the first graphics page was used) but also that memory could be located where the CGA's 16 KiB are, at B8000h..BBFFFh. Programs assuming a CGA (and direct screen access) would go ahead and paint their output into this memory instead. A timer controlled interrupt would now read the virtual CGA buffer at B8000h and transform its content into the real Hercules buffer at B0000h. On fast machines that could happen for every frame.
This was also supported by the fact that while many programs did direct screen updates, configuration was mostly done via BIOS calls, which could also be intercepted by the emulation and handled accordingly. For games with direct control of the CGA's registers, patches were sometimes available.
What were the limitations?
Most are related to the fact that the conversion of colour and resolution was done in software. To make it happen, the emulator had to steal the cycles to do so from the game. While not an issue with later PCs, it was a deal breaker early on.
Most notable Speed - Games got slowed down. While not much of an issue for round based or adventure games, it was real hurdle for real time/action games.
As well as Lag - One way to reduce the impact on the game performance was to skip frames. Doing the conversion only every second, third or fourth frame, reducing the effective frame rate. Again sometimes to an unplayable low when it came to (re)action games.
Weird Screen Format - Again due to the complexity of conversion, some emulators offered modes where less complex calculations were used by restricting the display area and colour resolution. As a result, only a part of the screen was used (or parts of the picture cropped) and colour information was dropped.
The other big drawbacks were ugly pictures due to the fact that converting a colour picture to monochrome always loses information. Unlike on a TV, there was no grayscale. Depending on the software this was compensated by replacing the colours by fixed patterns. This worked fine on pictures with sharp contrasts (i.e. always black lines in between) but usually only gave a rough impression of different coloured areas. With graphics based on colours (like with 160x200 mode) and fine details the result was awful. Keep in mind, these were just replacement patterns and nothing like real dithering.
And last, programs that manipulated the CGA's (6845) registers directly did not work at all. There weren't many and some emulators even had patches for common ones, still another hurdle to take.
*1 - Monochrome Display and Printer Adapter as the original IBM MDPA also offered a parallel interface. Obviously IBM assumed that an office user would need a printer interface anyway, thus creating the eventual first Multi-Function-Card :))
*2 - The large memory was meant to support loadable character sets and full graphics, as its developer wanted to use Thai characters.
*3 - Descriptions often mention 350 lines, but the last two weren't visible.
*4 - 720x350 at 50 Hz is, BTW, what can be done with a standard CRT when tweaking within the (European) boundaries.
The basic idea is to exploit the fact that both CGA and Hercules use the 6845.
I have the source code of an emulator at hand, so I can say what it does:
- it handles the mode-setting function of interrupt 0x10; for all non-Hercules modes, it includes tables of register settings to use to program the Hercules for the appropriate resolution and framebuffer layout;
- it piggy-backs on the timer interrupt to copy the framebuffers when an emulated mode is active (from 0xB800, which is where programs would write when using CGA, to 0xB000, the monochrome buffer).
There are quite a number of different emulators with different levels of success with various programs, so there are no doubt different ways of implementing the emulation.
The limitations are mostly related to hardware handling. Any program writing to the CGA registers won’t work, and any program relying on the Hercules vertical blank interval won’t behave quite right (CGA refreshes at 60Hz, Hercules at 50Hz). The status registers are different too, so polling CGA-style won’t work on Hercules at all. As mentioned by tofro, copying the framebuffers took a noticeable amount of time too (especially on CGA/Hercules-era systems), which would affect the system’s performance.
Just as a correction to a bit of the above: Hercules cards use regular MDA monitors. Their 350-line, nominal 50Hz mode (actually a bit below) isn't anything to do with regular broadcast monitors. They scan at 18.4kHz, which is a good way above that of typical TVs and low-rez monitors at 15.5~15.9kHz (and has the nice side effect of being effectively ultrasonic for most users - no more tube whistle... but a much worse one if you're high frequency sensitive). If you try feeding MDA/Herc syncs into a PAL TV, it could well blow up - and vice versa. Otherwise, there'd be no need for emulation - you could just throw regular CGA signals at it, and it'd work fine. The biggest difference between 50 and 60Hz broadcast monitors is the line count, and plenty of "15kHz" computer monitors can not only vary between those two standards without issue, but also other oddball settings like 45, 56, or 72Hz (with their own greater/intermediate/lesser number of scanlines - the latter having the bare minimum amount of blanking for a 200-line display).
It was, essentially, about as far as IBM were able to custom-tweak the circuitry of a common monochrome video monitor, with a long persistence phosphor on the tube to reduce the flickering effect, without having to go to the expense of a fully re-engineered high frequency item as later used for EGA (which retained much of the scan structure of MDA, but increased the line frequency closer to 22kHz, thus fully ultrasonic, and the Vsync back to 60Hz).
The monitors were somewhat adaptable to different setups, though; there's mention in some manuals for old ATI Wonder graphics cards about their Herc emulation also including the "special" / "little used" custom mode (Herc had NO ROM BIOS, all their modes were setup in software, so the "normal" ones were pretty much just matters of convention, and due to different clock crystals and slightly wonky maths weren't exact matches for the IBM standard anyway) of 640x400. Which was apparently used by some "eastern software" (presumably to better display Japanese/Chinese/Korean script) and wasn't guaranteed to work on all monitors. That mode, of course, would be just dandy for producing a better emulation of CGA, especially the hi-rez monochrome setting, as well as the highest resolution of certain 400-line / 25kHz "super CGA" machines... Unfortunately I have absolutely no idea of its setup, register values etc. The closest I've ever seen is a 90 column by 45 row (720x360 pixel, 8x8 font) textmode, emulated in graphics, which pushes the boundaries of both the available memory and what's displayable on a relatively inflexible MDA.