For quite some time I’ve had a very nasty bug in my game, where basically it would lock up whenever a sound was played through any sound device on my microbyte 386sx machine. What made this bug tricky to fix is that it worked perfectly fine on other hardware I had available and on the emulation I was using for testing (which was Dosbox).
I had already discounted any results from Dosbox, as it is widely known that the emulation is not hardware accurate. So I tested on the hardware I had available. Unfortunately I don’t have a lot of old 286 and 386 machines laying around, so I tested on the Microbyte 386sx and my Pentium MMX system. The big clue I got from that is that the sound code worked fine on the Pentium but not on the 386.
This is where I was stalled for quite a while, I tested much of the code and couldn’t figure out the fault. What I needed was another 286 or 386 machine to be sure it wasn’t just a quirk of the Microbyte, but this wasn’t something I could do easily. Recently I found an alternative solution that helped me solve the problem.
I have been watching some of Jim Leonard’s videos, as he makes some really good content about PC’s and is generally extremely knowledgeable. He had some of the same sorts of issues with developing DOS software using Dosbox for emulation, which is why he tends to use real hardware where possible. However he did recommend a PC emulator I hadn’t heard of called 86box.
So I downloaded 86box and fired it up. I was able to set up a virtual machine fairly quickly and found I could change some key configuration options I would later need. Most importantly I could replicate the crash in the emulator and experiment to find the cause.
Knowing that some aspect of the hardware configuration was causing the crash, I changed the configuration of 86box until the game didn’t crash, the key element turned out to be enabling the NPU. With it enabled the sound code worked a treat even on an emulated 386 system.
The reason for the crash, whilst difficult to work out, is actually quite simple. I have an interrupt hooked on $1C for playing sounds of any type, during the interrupt it would figure out the length of the next sound in timer ticks. This would use some simple floating point arithmetic.
Because I had configured the pascal compiler to use 80287 instructions and included emulation for when a NPU isn’t present the code would crash during the $1C interrupt. This would happen because of how the NPU emulation works. If a 286+ CPU encounters a floating point instruction and there is no NPU present it fires an interrupt, which redirects to the software emulation.
The problem plays out like this: In the main code there were some floating point calculations, these would use the emulation which could then be interrupted by more code also needing the NPU. This would mess up the internal state of the emulation causing a crash. This can’t happen with a real NPU because it can’t be interrupted mid instruction.
The solution was fairly simple, I turned off 80287 instructions and emulation and made minor adjustments to code so as to not require it. This got it working on real machines without a math-coprocessor and in 86box so I was quite pleased. I’m not entirely sure why I had used the 80287 code generation in the first place, but I can see why it persisted in my code for so long. Many of the machines I had tested on over the years were 486+ class computers, these all have the co-processor built in, so the problem wouldn’t appear. Dosbox didn’t expose the bug because there is no configuration option for turning off NPU support.
There is more work yet to do, such as implementing a lookup table to save on some of the calculations, and fixing other bugs. I’m now automatically packaging a download based on my most recent subversion revision which you can find here. I’m thinking about eventually hosting the binaries and code on somewhere like github.
0 Responses to “Bob’s Fury Update: Bug Squished!”