<< Newer Article #95 Older >>

Line of Fire conquered — mostly

As you may have noticed, MAME 0.94u5 has been released, and Line of Fire is working now. There were several problems with that particular game, all of which are interesting, and none of which had anything to do with the CPU interleaving that I originally thought was the source of my troubles.

In the end, it mostly came down to the divide chip. As I mentioned previously, the game will sometimes attempt to divide by zero. Now, the divide chip has flags to let you know that you've caused an error, but the game never reads them. It would then take the result of the divide-by-zero, look it up in a table, and use the resulting value in future calculations. The problem is that the table was only ~32 entries long, so when I tried returning 32767 as the result of a divide by zero, it read some random ROM location and used that instead of a valid value. To work around this, I am guessing that divide by zero either returns 0 or 1. I'll have to work with Charles to figure the exact details out.

But all that served to fix was the fast/slow/fast/slow speed at which you moved through the level, and which eventually ended up hanging the game. Once that was all better, the game would hang right near the end of the first level. At least that part was consistent.

First, though, I had to fix the jittery sprites. I was pretty sure there was no way this game would be that poorly done (though at the same time I think the Sega fanboys make a few too many assumptions that Sega would never have graphics glitches in their games). I first started guessing that the divide chip actually didn't do a full 32-bit by 16-bit divide, but rather maybe a 24-bit by 16-bit divide, or some other reduced accuracy version. This actually produced smoother results, but it screwed up a lot of other stuff too. Eventually I noticed that the value 0x8000 was being used as the divisor quite often, while at other times it was using values in the 0x7f00 range. If I treat those values as signed 16-bit values, then the 0x8000 would suddenly flip from +32000 to -32000, which seemed kind of odd. So I tried going back to a full 32-bit by 16-bit divide, but treating the values as unsigned, and suddenly things were much easier to look at.

But back to the hang at the end of level 1. I eventually put a trace on both the CPUs right near the end of the level, in order to see what was happening. It turned out that the main CPU would execute some code, then jump backwards into the middle of an instruction. This is a clear sign that something seriously bad was happening. On a hunch, I tried loading up the Japanese version of the game and looking at the equivalent code. Turns out one word in the World version ROM was wrong. But if the ROM dump was bad, then it wouldn't have passed the memory test in service mode. The only other logical explanation is that there must be a small error in the decryption key for the World version. Hopefully "The Doctor" will figure that out for me.

Related to the divide chip issue was the bug that made GP Rider behave strangely. My original divide chip implementation had us recomputing the results every time the dividend or divisor was changed. But it turns out (and is actually pretty clear from the schematics, now that I've looked at them again) that the divide is actually explicitly triggered by writing to a higher address. The reason this was important for GP Rider is that they would trigger one divide, and then load the dividend for the next divide before reading the result of the previous divide. With my original code, writing the dividend for the second divide was trashing the results of the first divide.

So, at this point, I'm pretty much done with X-board. There's a few small interesting bits left in Super Monaco GP involving extra sound boards, but that's pretty minor. What I'm really hoping is that someday a Last Survivor will show up. I love seeing new rare games come to life again. Even if it probably sucks. ;-)