CGA in 1024 Colors - a New Mode: the Illustrated Guide

Part #1 of the 8088 MPH writeup series • continued in 8088 MPH Final: Old vs. New CGA (and Other Gory Details)

By now you may have heard of the 8088 MPH demo, the winning entry in Revision 2015's Oldskool Demo compo this month.  It's been my pleasure to combine efforts with the likes of Trixter, reenigne and Scali to make it happen - not only did I get the opportunity to work alongside a bunch of extremely talented wizards of code, we also achieved what we set out to do: break some world records on the venerable (and yet much-maligned!) IBM PC, the mommy and daddy of the x86 platform as we still know it today.

One of our "hey, this hardware shouldn't be doing that!"-moments was extending the CGA's color palette by a cool order of magnitude or two.  How'd we pull that off? - reenigne has already posted an excellent technical article answering that very question.  To complement his writeup, I'll take a bit of a different approach – here's my 'pictorial' take on how we arrived at this:

8088 MPH 1K color CGA graffiti

Old dog, posing with new tricks. (Not pictured: blood, sweat, tears.).

The idea that such multi-color trickery was possible came to me some time ago, as I was looking at reenigne's code for patching up composite CGA emulation in DOSBox; messing with that patch during development gave me a much better picture of composite CGA's inner workings.  When I had ironed out the basic concept for this hack, I divulged it to reenigne for 'peer review' and for testing on real hardware.  Soon enough, we had an improved recipe:

  • Take two familiar (though officially undocumented) tweaks. Blend to an even mixture producing a new effect.
  • Add one crucial new trick – an ingredient of reenigne's devising.
  • Test and calibrate until blue in the face.

Below is my rundown of how it all fits together.  Fair warning: the 'target audience' for this writeup is people who may not be overly familiar with CGA, and/or come from other demo platforms.  As such, there's a whole bunch of background that's already well-known in CGA-land.  To prevent acute boredom, I decided to stick this TOC here – feel free to skip to the interesting part(s):


Old Trick #1: 16-color graphics over RGBI

A short crash course on CGA basics: the first graphics standard available on PCs supports a 16KB memory buffer, and is driven by an MC6845 CRTC (some later cards used alternatives).  Video output options are composite NTSC through a standard RCA jack, and the more widely-used DE9 connector, which outputs an RGBI signal (red, green, blue and intensity).  The latter is what most people think of when they hear "CGA"; this is a digital (TTL) signal, where each component can be either on or off, hence 16 different colors.  Despite what arcade hardware buffs would like you to think, CGA – in the strict sense – is NOT analog RGB, and never was.

Standard (BIOS-supported) graphics modes are high-resolution (640x200) in 2 colors, and medium-resolution (320x200) in 4 colors.  Not a lot of wiggle room here: in hi-res mode, only one of the colors (foreground) is redefinable – the background is always black; in medium-res, it's the background color that's adjustable, while the other 3 are determined by the infamously nasty fixed palettes.

Infuriatingly, in an almost-trollish move, IBM mentioned an additional low-resolution 16-color mode - "not supported in ROM" - with zero information on how to actually achieve it.  That nut was cracked pretty early on, though.

Low-resolution mode

This is no graphics mode at all, but a modified 80-column text mode. Basically, you adjust CRTC registers to get 100 rows of text instead of the usual 25; this gives you a character box of 8x2 pixels, a quarter of the normal 8x8.  Filling the screen with one "magic" ASCII character, 0xDE, effectively splits each character cell into left and right "pixels", corresponding to the background and foreground colors.  These two colors can be individually set to any of the 16 CGA values, as in any CGA text mode, as long as you remember to turn off blinking.

CGA low resolution mode

CGA low resolution mode

So there you have it; 160x100 @ 16c.  This mode was used in games as early as 1983, but never got wildly popular - probably because of the "snow" that plagues IBM CGA cards in 80-column mode, unless you burn some costly CPU time to avoid it.

The Macrocom Method

You may ask: since this is text mode, what's stopping you from using the entire ASCII character set? Other than a healthy respect for your own sanity, nothing really!  This was first attempted around the mid-'80s by a few brave souls at Macrocom, who combined the 100-rows trick with ASCII art, to create what Trixter once succinctly called "ANSI from hell".

CGA ANSI from Hell

As you can see above, I've experimented with this a little.  With judicious use of the character set, you can almost fool somebody into thinking that this is a 640x200 mode - although there's some inevitable "attribute clash", a little like the ZX Spectrum: each 8x2 character cell can contain only two colors, foreground and background. Also, you have to be a bit of a glutton for punishment to actually draw in this mode from scratch... but that's a subject for a future post.

This trick isn't directly relevant to our demo: we were targeting composite displays. Even if CGA's composite output didn't have its share of bugs and quirks in 80-column mode – which it does – there'd be no way to see this level of detail over NTSC.  There's a reason I mention this effect, however; the idea behind it does figure into the story.  But more on that later.

Old Trick #2: 16-color graphics over composite

Digital RGB monitors were still a luxury item at the time of CGA's introduction, and IBM itself didn't offer one until a couple of years later, coinciding with the release of the PC/XT.  But CGA also provided composite output, giving out (mostly) NTSC-compatible video. At the expense of resolution, there's more fun to be had here with color.

Direct colors

Composite CGA, 16 direct colors

On the composite output, the familiar 16-color CGA palette is represented by a series of color signals, whose hue is determined by their phase relative to a reference signal (the NTSC color burst).  The frequency of the NTSC color clock (3.579545 MHz) works out to exactly 160 color cycles per active CGA scanline.

These are directly generated by CGA hardware as color signals, so we'll conveniently call them "direct colors".  IBM had two main revisions of the CGA, which produce composite video somewhat differently: 'new-style' cards contain additional circuitry, which helps the palette match its RGBI counterpart a little more closely.  For the demo, we standardized on 'old-style' cards, simply because we happened to have done more testing on those (with somwhat better results), so all images in this post will reflect 'old-style' CGA colors.

If these 16 direct colors were all we had, it wouldn't be a whole lot of fun, would it?  They're also shockingly ugly, esepcially on an old-style CGA, which doesn’t help matters either.  Just look at that palette... gross, dude.  Luckily, there's a way to go one better.

Artifact colors

Due to bandwidth restrictions, NTSC video doesn't fully separate chrominance (color) from luminance.  Effectively, any high-resolution detail – that is, detail with higher frequency than the NTSC color clock – gets 'smeared' when the signal is decoded. This is responsible for the characteristic color bleed, seen in the form of fetching little fringes at the edges of text characters and other fine detail.

Remember how you get 160 color cycles per active CGA scanline? Standard CGA gives us either 320 or 640 active pixels per scanline, depending on the video mode.  Ergo, we can switch pixels on and off at 2x or 4x the frequency of the color carrier.  Since this high-frequency detail cannot be fully separated from color information, the upshot is this:

The hue of a pixel, or a fringe (transition between pixels), depends on its position within the color-cycle period.
NTSC color wheel

This NTSC color cycle is sometimes represented as a wheel: one complete period of this cycle equals a 360° revolution around the color wheel, and we have 160 complete revolutions per scanline.

Let's say we're in hi-res (640x200) mode, where 4 pixels fit into one such color cycle: moving one pixel left or right translates to moving 90° along the wheel, in either direction, and accordingly shifts the hue by 90°.  Likewise, in 320x200 mode, we move in 180° increments of hue-shift.

In short, manipulating detail at high resolutions is effectively a method of generating color; being an artifact of NTSC's imperfections, this is known as artifact color.

CGA composite output: fringing and artifact colors

Various filters can be (and often are) employed on the receiving end to recover some of the high-frequency detail, reducing color bleed and making edge transitions somewhat sharper.  We're still dealing with technology, not magic, so full separation of detail and color can never quite be achieved, and the trade-off is a whole new set of artifacts (in the form of "echoing" or "ringing").  This trade-off may or may not be acceptable, depending on what you're doing, but the above image doesn't attempt to reproduce any such filtering.

Solid artifact colors

All this business of "fringing" and "bleeding" sure sounds like a bummer, and that's exactly what it is: the unwanted side-effect of a less-than-ideal encoding scheme.  But like any good flaw, it can be turned into an advantage by an enterprising soul, and this is where we get to the fun part (your mileage may vary).

When you look at the interplay of color vs. detail over NTSC, a very handy fact becomes apparent:

Any periodic composite signal, with the same frequency as the color carrier (160 per line), will be decoded as a solid, continuous color.

Our 16 direct colors are exactly this type of periodic composite signal.  But hold on – with some simple high-resolution pixel-pushing, we can manually put together our own periodic waveforms!  Any pattern of dots will do, as long as it repeats at the right frequency.  This lets us achieve solid colors that lie outside the direct color palette.

CGA solid artifact colors 1

The "classic" way of doing this on CGA is to set up BIOS mode 6 – 640x200 in 2 colors, white on black – and set the color-burst bit (which is off by default, for a B&W picture).  At this resolution we can squeeze 4 pixels into a color clock period, and at 1 bit per pixel, there are 16 possible patterns – giving us 16 solid artifact colors.

This is pretty much the same technique used by Steve Wozniak to generate color on the Apple ][.  In fact, on an old-style CGA card, these 16 colors are identical to the 16 low-res Apple colors (although you couldn't get them on a poster, like Apple owners could).  More to the point: the pixels themselves are white, which carries no color information; it's the detail that does the deed.

*But wait, there's more!*  Despite popular wisdom, CGA lets us one-up the Apple, and then some.  OUR underlying pixels don't have to be white: in 640x200 mode, we can play with the palette register and set any of the 16 direct colors as the foreground (background is always black).  By using the same pixel patterns with a different foreground color, we get 16 entirely new sets of artifact colors, with 16 colors each.  We can only use one such set at a time, but we get to pick and choose what our 16 colors are.

Then there's 320x200 mode, which supports a palette of 4 direct colors.  Only one of those, color #0 (background), is freely selectable.  For the rest, intensity may be on or off, but we can only use green/red/yellow or cyan/magneta/white; the undocumented cyan/red/white palette involves disabling the color burst, making the composite picture greyscale.

Since our pixels are twice as fat in this mode, only two of them can squeeze into a color-clock cycle – but at 2 bits per pixel, the total count of artifact colors is still 16.  The possible combinations of palette, plus the user-defined background color, provide us with a whole slew of other 16-color sets.

CGA solid artifact colors 2

This may be a good place to correct a bit of a misconception.  Since we have 160 color cycles per scanline, many people treat CGA's graphics modes over composite as 160x200 "modes", but that's not quite accurate.  Our effective color resolution is indeed 160x200, and it's impossible to get finer detail than that using solid artifact colors.  But as we've seen, on NTSC the pixel grid and color grid are NOT one and the same – which makes the question of horizontal resolution a bit fuzzy, depending on how you're sampling and/or filtering the signal.  It even varies with the specific color waveforms you're using.

IBM itself never documented any of these artifact color tricks, other than one oblique reference to "color mixing techniques" in the PCjr tech ref (if I'm wrong about this, drop me a line and link me!).  The concept is fairly old hat, however – it was used in games very early on; some of the first ones I can think of were Microsoft's Decathlon and Flight Simulator, both in 1982.  And the limitation has always been the same: the maximum simultaneous color count you can get over composite CGA is 16.

....Or is it?  On the off chance that you've been following me so far, and you're still reading, you may have an idea of what the next step is.

256 colors

We've already observed that our choice of 16 artifact colors depends on the palette and color register settings.  One fairly obvious strategy seems to suggest itself here – change those registers at particular scanlines on every frame, and get >16 colors on screen that way.  Right?

CGA 256 colors

This has been done before on CGA, and you can actually exploit this for 256 colors (as proven by reenigne - see the image to the left), but that's not how we did our multi-color hacking in the demo.  We were actually toying with the idea of including a static screen that uses this technique, but I didn't have the time to pursue this; if anyone manages to compose some nice artwork using this method, I'd love to see it – that's gotta be a bit of an artistic challenge.  But no, the way we wrangled more color out of CGA is a whole other shenanigan... which I came across by equal parts chance and morbid curiosity.

Recall how any color/dot pattern of the right length (four repeating pixels in 640x200, or two in 320x200) produces a solid color on a composite display?  Back when I was testing composite emulation for DOSBox, that fact was fresh in my mind.  At around the same time, I was experimenting with the "ANSI from Hell" graphical hack detailed above; that's purely a text mode / RGBI trick, but it requires a close familiarity with the ROM character set... closer than most sane people would want or need.

Let's take another look at a particular section of the CGA ROM font, in 80-column mode, with the top 2 scanlines highlighted:

CGA ROM font subset

At this point, if you're a visually-oriented person, and if you've been following my drift, you're probably catching on.  Don't see it yet? Here's a fatter clue:

ASCII char 0x55

See those top 25% of the character bitmap?  Two dots of foreground and two dots of background, doubled horizontally across.  We're in hi-res/80-column mode, so there are two color cycles per character... corresponding exactly to those two matching halves.  And those top two scanlines are identical.

That's just the type of repeating pattern that gets us a solid artifact color over NTSC.  In fact, it's the very same waveform that 320x200 mode lets us play with.  Except that now we have it available in text mode: you know, where we can freely assign a foreground AND a background to each character, from the 16 direct colors.

That's 256 possibilities right there... this is the part that made me go "I have a cunning plan", in my best imitation of Blackadder's Baldrick (just not out loud).  Indeed, it's possible to achieve >16 colors on CGA without any flickering, dithering, interlacing or per-scanline effects.

Here's what the possible combinations work out to:

CGA artifacts - ASCII char 0x55

512 colors

Oh, we're not done yet: once that lightbulb went off over my head, I had another look at the CGA ROM font to see if any other useful bit sequences emerge.  There are a few character bitmaps that give us the exact same waveform as 'U' does – 'H', 'V', 'Y' and '¥' – but only one with a different suitable bit sequence right where we need it: 0x13, the double exclamation mark ('‼').

The top two scanlines of 'U' give us a bitmask of 11001100 for foreground/background; '‼' is 01100110 – a single shift to the right, or a 90° shift in phase.  This perfectly complements 'U' in terms of having a well-rounded palette, because we get all the colors that the "...1100..." waveform has to offer: going from 'U' to '‼' shifts the phase by 90° (0110); 180° and 270° are achieved by flipping the foreground and background colors for 'U' and '‼' respectively – the same as going '0011' and '1001'.

CGA artifacts - ASCII char 0x13

Okay, we've pushed the envelope even further: 512 simultaneous colors!  Granted, the real number is lower, because a good few are duplicates (and others are very close).  But 512 seems to be the limit for this technique: no other characters in our font fit the bill for solid colors.  The CGA character ROM does have an alternate 'thin' 8x8 font; but, besides the fact that you'd have to mod your card if you wanted to use it, the 'thin' font has none of the magic bit patterns in the right places, which makes it useless for our purposes.

My kingdom for redefinable characters... alas, when you're dealing with old PC hardware, IBM's penchant for cost-cutting over innovation can always sneak up from behind and ruin your day – even in the most unusual of places.

Still, I was pleased with my little discovery: extending the palette by a factor of 32 has to count for something, right?  At this point, I shared my ideas with reenigne.  Little did I know that he'll promptly come up with a new devious scheme to double our color count yet again...

1024 colors

This part is some next-level CRTC black magic which I could never have figured out by myself – I'm just a graphics guy; you might as well ask me to wait for a full moon and chant the MC6845 spec-sheet backwards in hexadecimal.  All credit goes to reenigne for this particular bit of mad science, which, despite its complex execution, stems from a wonderfully simple idea: our fixed character bitmaps don't play nice with what we're trying to do? No problem – we'll make them play nice, or else.

ASCII chars 0xb0, 0xb1

See, there are two additional characters whose very first scanline could be used; problem is, the second scanline is different, which would ruin our solid color effect.  These are ASCII codes 0xB0 and 0xB1, the 'shaded block' characters. It would be quite convenient if we could just tell that offending second scanline to buzz off, wouldn't it? As it turns out, we can.

The lowdown on how this is done is all in reenigne's writeup, which is linked to at the top of this post.  But this is the basic idea: by starting a new CRTC frame every other scanline and twiddling with the start address, it's possible to lay down our character rows so that the first scanline of each gets duplicated twice!

Now we can make use of those two extra characters, and doing so gets us two more 256-color sets:

CGA artifacts - ASCII chars 0xb0, 0xb1

Naturally, there are downsides: having to mess with the CRTC every couple of scanlines is quite taxing for the poor 4.77MHz 8088, so there's not much you can do with this other than static pictures.  The 512-color variant, using only ASCII 0x55 and 0x13, doesn't suffer from this – it's basically "set and forget", requiring no more CPU intervention than any 80-column text mode (the familiar overhead of avoiding snow).

Then, there's that other problem which plagues 80-column CGA on composite displays... the hardware bug that leads to bad hsync timing and missing color burst.  There are ways to compensate for that, but none that reliably works with every monitor and capture device out there.  This proved to be an enduring headache in calibrating, determining the actual colors, and obtaining a passable video capture of the entire demo... but that's all covered elsewhere.

At any rate, we now have 1K colors on a 1981 IBM CGA, at an effective resolution of 80x100 'chunky pixels'.  'Chunky' describes the memory layout, but it also applies in the visual sense: we're really plumbing the depths of resolution here.  160x100,  that's as low as you could go? allow me to snicker, IBM - "low-res" just got lower, baby!

One might object that this isn't a lot of canvas.  Yeah, yeah: 80x100 is a bit on the cramped side, 'artistically' speaking; but the limitation is part of the challenge, as it has always been in demos.  You can keep your fancy 4K monitors - 0.008 megapixels should be enough for anybody.

CGA flowergirl 1k colors

When we first showed Trixter the 'proof-of-concept' 1024c drawings, his response was, and I quote: "HOLY F!@#$%G SHIT. WOW. I must know how this works!!".   Achievement unlocked: getting THAT out of a veteran 8088/CGA hacker and demomaker is, by itself, almost as good as... well, joining the team, 'making a demo about it' and winning the oldskool compo. :)

That's about it for my writeup.  If you made it this far, congratulations!  There's more I could write about the tools and techniques I used to actually compose these graphics... but we'll get to that some other time.

Continued in part 2: 8088 MPH Final: Old vs. New CGA (and Other Gory Details)


Absolutely brilliant. Thanks for this detailed write-up !

Anonymous says:

Lovely! :)

Amazing. This crushes anything I achieved with my graphically superior C64 using scan line manipulation - and I thought I was a genius at the time. sobs

Anonymous says:

Sir, I am honoroured to live in the same Standard History Eventline as you do. It all sounds so obvious.

I wonder what ingenious guys like you could do with a 1978 near-defunct Hardware. In space. Like ICE/ISEE-3

BLuRry says:

Having implemented the Woz-style 16-color mode (including the Y'UV conversions) I have to say hats off to you guys for pushing the limits. Excellent write-up too!

Sly says:

As far as I remember, "frogger" game for CGA used 5 different colors. How exactly it was done, I wonder.

VileR says:

You remember correctly - CGA Frogger starts each frame with a blue background, and sets it to black at a particular scanline down the screen. Jungle Hunt and California Games did similar things (all rely on rather precise timing and/or polling the CGA status register, since there are no raster interrupts).

Anonymous says:

Beautiful and informing.

BLuRry says:

As an emulation author, I have done quite a bit of study on how to emulate the NTSC color fringe using sliding windows. Your description of the artifact behavior is spot-on and well-done! It might help the folks at home to look at YU'V-to-RGB conversion formulas in order to better understand the math involved. But discovering how to use other colors in text-mode, that's just outstanding!

As it turns out the color fringing behavior is present in Apple // graphics as well, just never really utilized. A blue pixel fades in/out of black and so on. You could represent the apple screen as having 560x192 resolution, but some pixels come out as different colors despite the apple only produces 140 color cycles -- if you move a single pixel from left to right it will still appear as if it were in 560 places, it will just change colors along the way.

The best way I could exploit this is by a brute-force method, where my goal is to find the best combination of bits (the apply uses 7 out of every byte) to represent 7 input pixels. I just look for the shortest (perceptive) color difference for a group of 7 pixels, turning on each bit on and off one by one. Then using dithering I spread the error to the pixels below, etc. This has a nice side-effect of giving me the fullest color representation of an image while retaining 560 pixel-width detail. No you can't see it on a TV screen clearly but it looks nice and smooth all the same.

Anyway, well-done. You guys are clever gents! When you get a chance, have a look at some of the recent graphics demos by "French Touch" who have been able to do some crazy graphics hacks on the Apple // series (especially their "Crazy Cycles" demo which will break most emulators but not mine. ;-)

VileR says:

BLuRry: thanks for the feedback!

Funny that you mention Apple ][ NTSC emulation, as I just put up a new post on that subject - to be fair, I wasn't aware of JACE until now, so I didn't consider it when writing that post. I'll have to give it a go with those demos you mention :-)

Anonymous says:

Twice as fat...

Would it be possible to package up the 1K CGA mode drawing code into a library?

kluttpendyl says:

It's almost 3 at night here, and I should be sleeping, but I just had to read through this entire writeup. This is absolutely amazing, great work!

Unknown says:

Saint Mary Francis!
My jaw just unlocked and fell of 8()

MDV says:

Unbelievable. I was browsing Google for some help with ANSI text and found this page by accident. It doesn't even seem possible!

Ollie says:

Jesus Christ!!! As a former amateur programmer, I came here from a different thread: C64 raster-handling tricks which I guessed for long but never found explained until now. But 1024 CGA is simply genius stuff. Absolute respect and admiration to people involved.

Ed Coolidge says:

If switching between alternating fields was used to produce the same solid color on both scanlines, what would you get if it was used to set a different bit/color pattern on each scanline separately? I know you said reenigne could use that hack, but didn't. What if you added that hack too?

VileR says:

@Ed Coolidge: if you could use different bit patterns on every scanline, you would have the same "palette" at double the resolution (80x200 'pixels'). But at two scanlines per character row, the non-programmable CGA font doesn't give us a free choice of such patterns to use... and if you go for one scanline per row, a full-screen picture would need twice as much RAM as the CGA's 16K. The "mugshots" section of 8088MPH (before the end credits) does exactly that, which is why it only covers half the screen. :)

The mentioned hack that we didn't use has to do with modifying the card's color registers at particular scanlines, but that only works in graphics mode (in text mode it'd only affect the border/overscan color, not the active area). Anyway, that trick still gets you 16 colors per scanline at most.

David Given says:

Back in 198<something>, BBC Micro Elite changed screen modes halfway down the screen --- so the top half was 320x256 monochrome, and the bottom half was 160x256 4-colour. This allowed the view out of the cockpit window to be high resolution but your cockpit instruments were in colour. Naturally this would only work when there were the same number of bytes per scanline with the two modes.

I would love to see what the final 1024-artifact color technique could produce when combined with the changing of colors on every scanline, plus changing of video modes (and/or disabling of color burst) partway through the image to produce a combination of sharp detail and a wide color gamut.

Outside of 8088 Land, though...
Having access to an NTSC Composite Display plug-in for non-DOS emulators (for example, emulators of old game consoles such as the Super Famicom and the Mega Drive) would be incredible stuff. Combined with CRT emulators such as the one used for MAME, it has the potential to make everything look exponentially more awesome.

Unfortunately, 90-degree shifts on the NTSC artifact color wheel are not possible on the Mega Drive, as each scanline can only have a maximum of 320 or 256 pixels, and the Super Famicom has 256 pixel and 512 pixel modes, but no 320 pixel or 640 pixel modes.

And then, of course, there is the issue with VDP circuitry screwing with the composite signal to try cleaning it up...

On the plus side, there is a theoretical maximum of 61 colors per scanline on the Mega Drive (four layers of 15 colors each, plus a background color), even more if you use the Shadow and Highlight mode on the Sprite layer, and since each indexed color represents a 9-bit RGB direct color... and when combined with interlaced modes to double the vertical resolution, you can have at least 448 scanlines to work with. It would technically be 224, with the second frame being offset slightly, and in order to produce artifact colors correctly both scanlines need to be nearly if not completely identical, but you would finally be able to achieve a vertical dithering effect and artifact colors at the same time.

Really cool!! Was using CGA/VGA mode to demonstrate elementary graphics (peek/poke) for a hack session using Forth --- came across this -- outstanding achievement and great writeup!

Mario says:

There are quite a few duplicate colors, there are actually only 944 colors in total.

Mario says:

It is still very impressive though. (adds on to my other comment.)

MrMadguy says:

Can you please answer 2 noob questions about CRT?
1) VGA 320x200x256 uses 640 timings, but produces 4 pixels per character clock, instead of 8. So, is 160x200 possible on "Dot clock div 2" mode, i.e. with 320 timings?
2) About 320 timings for 160 mode. I needed to investigate them in order to figure out timings for 180 (i.e. 360) mode. Why can't be use 640 timings, divided by 2? Cuz, you know, VGA is analog monitor and there is not difference for it between 320x200 and 640x400. Timings are the same. Only difference - is at what rate pixels and lines are being outputted? Why do we need special timings? What I don't understand - is why retrace end = 0? If it's 0, then character count can be only 00h, 20h or 40h. It can't be 20h, cuz retrace start is 2Dh. It can't be 40h either, as horizontal total is 31h. So, it's 0 and retrace ends right before starting to display image. I.e. without any porch. How about left overscan area? What can it be right?

In this great article, '?' appears four times as "0x13, the double exclamation mark". Please change to proper Unicode character: ‼.

VileR says:

@Maciej: some encoding error must've creeped in there during migration - thanks, fixed now.

lorenzo says:

I wonder if this trick could be somehow exploited with other ancient machines like 8-bit home computers... imagine 512 or 1024 colors with C<64...

NoNT says:

What about PAL? :)

VileR says:

CGA never did get a PAL version. Technically the MC6845 controller has no problem producing PAL timings (I did that once purely by accident...) but the picture would still be black and white.

KJ says:

This is genuinely demented in the best possible ways. Well played...

schrottvogel says:

Absolutely marvelous!! But say, can't you define your own charset in graphics mode for ASCII 80h..FFh using the INT 1Fh vector? And then you could easily have all four 90° rotations using your own character definitions, and -- if I understood you correctly -- get those 1K colors without any per-scanline CRTC hacking... no?

VileR says:

@schrottvogel: yep, graphics mode allows redefinable charsets, but it also lets you address pixels directly anyway, so you gain nothing by relying on characters.  Besides, CGA graphics modes don't simultaneously provide all the required 'direct' colors, so the maximum for artifact colors is still 16 (see 'Artifact Colors' section above).

schrottvogel says:

Uh yeah, I completely forgot that we're in CGA text mode :)

This is absolutely amazing and truly dives into the depths of "hacking" bits to the limit. That image of the "Flower Girl" in CGA rivals that of what you could do with traditional EGA and actually gives old-school VGA a run for its money.

This is an amazing write-up and really shows your passion and talent for hacking bits to the point where you almost squeeze three possible values from one bit. :)

Bravo and amazing work -- that's some amazing talent.

ropersonline says:

@VileR: You wrote that CGA never did get a PAL version. That's true for original IBM CGA, but I just heard that perhaps at least some models of the Amstrad PC20, aka Sinclair PC200 (wedge-shaped semi-compatible PC clone; see Wikipedia) may have included a PAL-compatible RF modulator and perhaps even further CGA-to-TV conversion circuitry, and may have been able to display either composite or perhaps even converted RGBI CGA on PAL TVs in colour. This is just a rumour at this point but might be worth looking into if anyone has access to these rare and somewhat nonstandard machines.

Finding out the truth about that might have implications in terms of showing whether it would be possible to construct a CGA-to-PAL colour TV adapter (as a piece of new retrocomputing hardware – I don't think such adapters ever existed on their own back in the day).

Wasl33t says:

God bless you super geeks for this excellent! Such amaze, on hardware never meant! Thank you very!

ropersonline says:

Further to my earlier comment, actually it turns out that's briefly covered on this well-known page <>, which does have an "Amstrad PPC / PC20" section, where the unusual CGA RGB-to-PAL colour output is mentioned.
The PPC portable models covered in that section were different machines that perhaps would have been served better by an own section, but that said, the 1512, the PPC and the Amstrad PC20/Sinclair PC200 were all relatively similar.
A recent "RetroManCave" video covers all of these machines: <> (Fair warning: Has ads.)
Anyway, the general consensus seems to be, these "wedges" weren't NTSC artifact-capable, so 8088MPH wouldn't have looked its best on those clones.

VileR says:

@ropersonline: it's pretty interesting that Amstrad went through the trouble to do that. I'd imagine that the biggest difficulty of maintaining real CGA compatibility with PAL output would be the 50Hz vertical refresh rate. I couldn't find any details on how the PC20(0) handled that, at least not in those links, but I suspect that the answer is "not very well".

There was such a thing as "PAL60" (more or less PAL-formatted color using NTSC timings), but I don't think that was ever a standard. In that youtube video, the squished aspect ratio tells me it's probably 50Hz, with the active display area letterboxed, and I also see some really overbearing crawling diagonal line artifacts. Gotta assume that the TV output was more of a kludge than anything intended for serious use.

A.J. O says:

Incredible! Such a brilliant use of composite CGA graphics, but I'm now wondering, if there's nothing stopping you from using the entire ASCII character set, then why not make use of the Macrocom Method on a composite display, sacrificing the continuity of the colors in exchange for even more of them and approximately double the horizontal and vertical resolution (up to around 160x200)? You also wouldn't be constrained to eat up extra CPU time in order to duplicate the first row of characters 0xB0 and 0xB1, meaning that this might even make it practical for games. Just curious what your thoughts are about this; I really enjoy reading about this kind of thing!

VileR says:

@A.J. O: Yep, that's very much possible. In fact 8088 MPH already has an example of that: the "mugshots" section uses arbitrary ASCII chars, although that's a single frame with one scanline per character; so it only takes up half the screen, but that second scanline doesn't interfere with the color selection.

Of course, the difference is that you don't get solid colors, but specific patterns that depend on the character/attribute - and also on the preceding and following chars, because you're up against the limit of chroma resolution, so the analog color transitions across character boundaries have just as much an effect on the result. This makes for even more possibilities, but it also means you can forget about "drawing" in this mode, since you can't go around placing discrete 'pixels' at arbitrary locations.

It's more practical to use a pattern-matching converter, and that's what reenigne wrote to do this - he's extended it into a program named CGAArt, which you can find here along with some output examples. And yes, it lets you use the second scanline as well. :)

Josh J says:

Hello, first off: this is super cool! Really helpful and I've been using these images to help develop an NTSC signal demodulator to ensure I get proper artifact colors.

The colors I'm generating match perfectly to yours for the 1bpp version, however I'm getting wildly different colors on any of the color-modulated outputs. What I've noticed in all of the diagrams where you have color artifacts, the baseline colors in the blocks where background and foreground colors are the same don't match the baseline color. For instance, the most obvious example of this is the right half of the image labeled "320x200 (2bpp) / palette 0 (green/red/brown) blue (#1) background" - It seems to me like the top color (blue) and bottom color (the orange) there should end up being blue and orange, respectively, as neither of those bars have any alternating pixel values to introduce artifact colors ... instead, the top is a purple and the bottom a green! Is there some additional color shifting going on here that I'm not following? What's causing that additional color shift, if you don't mind me asking?

Thanks, and great work again on this, this is a massively impressive hack for hardware that, growing up playing gross CGA Maniac Mansion, I would have never guessed could be pushed as far as this!

VileR says:

@Josh J: Right, those two colors are 'direct' colors, no artifacting going on there. They just appear very different on RGB vs. composite, because the CGA doesn't really derive its NTSC colors from their digital (R,G,B,I) counterparts. It just generates a basic NTSC-frequency color signal, and phase-shifts it to produce the different hues. (The later 'new-style' CGA does modify the Y-component with a weighted sum of the RGBI signals, but that just affects luminance.)

In the "Direct Colors" section there's a shot of the 16 possible CGA color values over composite, without artifacting. #1 (RGBI blue) and #6 (RGBI brown/orange) are respectively the purplish and greenish colors in that artifacted 2bpp palette.

If you need precise YIQ values for those 16 colors, the DOSBox or PCem/86box source code should have what you need (as derived by reenigne from his research of the hardware). The CGAArt program linked in my previous comment could help too.

Also: Maniac Mansion is great, but they flubbed the composite CGA palette by just reusing the same numeric values from the 16-color RGBI versions as their artifact patterns. I guess that's where the gross came from :)

Kevin de Vries says:

Super Awesome !

Well written and explainged, I really enjoyed reading it and learnt a lot from it.



richinseattle says:

very cool, thanks!

Chester says:

This is an amazing write-up of an incredible feat, my sincere congratulations.

In addition to the correlations with the ZX Spectrum color clash, the Apple II color generation and "racing the beam" on the Atari 2600, I'd also notice the usage of the top two rows of the characters (and subsequent single row by resetting the frame) is also reminiscent of "pseudo hi-res" software tricks on the ZX81.

Thank you again for the great time I had reading it (and the couple re-reads I'll need to understand it all, it's a lot of cool info!)


Amazing read, nice to see mutliple approaches summed up in one place!

excellent finding, entertaining writeup! impressive! many thanks,

db says:

Fantastic writeup.
Can I ask where the original "flower girl" image comes from? I can't seem to find it anywhere on the web.

VileR says:

@db: Thanks! The reason you can't find a source on the web is because none exists - the images are all originals created specifically for the demo (and anyway, the compo rules were pretty clear-cut on that sort of thing IIRC).

Write a response:

* Required.
Your email address will not be published.