Shortly before our release of 8088 MPH at Revision 2015, another 8088+CGA production surfaced at Gubbdata 2015:
This production was GP-01, by Genesis Project. One the one hand we were happy to see more people targeting the 8088+CGA platform. On the other hand, we tested it on our real machines, and it didn’t actually work, it’s a ‘DOSBox-demo’.
Here is a quick-and-dirty video of what happens on a real IBM 5160 with real IBM CGA (this is my machine, the one used for capturing 8088 MPH at the party):
Because it was so close to Revision 2015, and we did not want to draw any negative attention prior to the release of 8088 MPH, we did not report this at the time.
However, once Revision was over, and the attention around 8088 MPH had died down somewhat, I decided to look into this demo some more, and see what the problems were, and if I could fix them.
In short, we have the following issues:
- Music doesn’t play, it just generates one constant tone
- Screen is wrapping around vertically
- Keyboard locks up
- CGA snow
So, I reverse-engineered the demo, and inspected each of these issues, and tried to fix them. Let’s go over them one-by-one.
When I looked at the timing routines, it quickly became obvious why they weren’t working: The demo uses int 70h and port 70h/71h. That is the CMOS realtime clock, and requires a second interrupt controller, neither of which 8088-class machines have. These weren’t added until the later AT-standard, which was introduced with the 286 CPU. So on a PC/XT-class machine, the code simply enabled the speaker (causing it to play at whatever frequency it last used, apparently the bootup beep in this case), and then nothing happened, because the interrupt handler for the timer was never called, because that specific timer hardware doesn’t exist.
So I rewrote timing based on the standard timer interrupt, the same way as CGADEMO and 8088 MPH do it.
The problem with the screen wrapping was that the demo tried to set up 80×50 and 80×100 tweaked textmodes, but it only initializes a few registers. Apparently enough to make DOSBox work, but not enough for actual hardware, where you have to take care to generate a proper 60 Hz image with 262 scanlines in total.
In this case, what happened is that they changed the character height from 8 to 2 lines (which results in all character-based vertical timing being 1/4th of what it was before), but they did not adjust the rest of the code to make sure the visible area still has 200 lines, and then 62 lines for border and vertical blank. So as a result you only got 50 lines in total, then a few lines of border+vbl, and then the frame started over, effectively making it refresh at 4*60 Hz. Since the monitor still works at 60 Hz, it just displayed 4 of these frames on top of eachother. So I fixed up that code as well, to get a proper image on real hardware.
The keyboard-routine hooks into int 9 and then checks port 60h of the keyboard-controller for a keypress, but it did not disable and re-enable the keyboard-controller so that it would generate an interrupt again for the next keypress. Which is why it would get stuck after one keypress. So I fixed that as well.
So far, that led to this quick-fix version:
Now it was fixed just far enough to notice some new issues:
- Music plays low buzzing sound when it should be silent
- Logo has weird wraparound issues when scrolling into view
- Scroller is not smooth
Let’s fix some more!
Looking at the music code again, it does not handle silence at all. The code is set up to just play note+duration data, and silence is just a note of 1 Hz. Apparently that isn’t audible in DOSBox, but you get this buzz on real hardware. So I rewrote the code to turn off the speaker when a note value of ‘1’ is encountered (value ‘0’ was already taken for ‘end of music’, making the music loop).
This is another thing that apparently happens to work in DOSBox, but not on real hardware: the logo is just being drawn to the screen with no clipping whatsoever. Because real CGA memory wraps around, you see the logo at the top of the screen when it is being drawn below the visible area. Namely, we are using 80×100 textmode, where each character is two bytes: attribute byte and ASCII value byte. So we are using the full 16KB of CGA memory for the onscreen buffer. On real hardware, this physical 16KB is mapped into the B800 segment multiple times, so writing beyond the first 16KB will cause the wraparound. Another thing that was not too hard to fix: just add some clipping to the blit-routine. Since the logo just scrolls vertically, it was simple enough to just check after each scanline to see if the value of the DI register would exceed (160*100).
The scroller was somewhat weird: there was some delay code to control the speed of scrolling, but it was just a countdown, so it was not trying to sync to the display at all. Again, this was very easy to fix: even in textmode you can just poll the CRTC registers for vsync status. The text was small enough and the screen position was low enough to get perfect 60 Hz scrolling on the frontbuffer with no flicker (in this case the snow is actually somewhat useful: you can see exactly where the CPU accesses video memory, so you see snow in the top part, where it updates the scroller, and no snow from the moment it starts polling for vbl).
This got us as far as this version:
Well, not bad… except for all that snow!
Is there a way around snow? Well yes, in theory, as you have seen in 8088 MPH’s plasma effect. Problem is, it requires you to throttle the writes to video memory, making all effects much slower. I decided not to bother with that, because it would be a lot of trouble to rewrite the effects like that, and the demo would no longer look as intended.
However, you’re in luck: many CGA clones do not suffer from snow. Here is what it looks like on such a clone, an ATi Small Wonder:
So there we are, we are running it on actual hardware, and it looks and sounds pretty much as intended, based on the DOSBox capture.
If you’re interested, you can download the fixed version, including reverse-engineered assembly listing here.
I hope there will be more people doing 8088+CGA productions!