Monday, May 21, 2012

Verification

I implemented the AI code to handle automatically driving the Ferrari in Attract Mode. This means I've been able to test the accuracy of the ported engine in a number of ways, which is where my time has been spent recently.

The AI code works by reading the upcoming road layout and traffic data. It outputs appropriate acceleration, brake and steering values which are read by the standard game logic. I've been able to compare my ported game engine against the emulated game engine to ensure key values are identical.

I made both MAME and my port spew out a selection of values relating to the AI, car road position, car x coordinate, car speed and so forth. By comparing the outputs, I discovered and fixed subtle bugs that weren't noticeable by playing the game.

Unfortunately, about 330 frames into attract mode the values diverged. The difference was subtle. The culprit was the Ferrari handling logic reading different x coordinate values from the road data between versions. Assuming the road rendering code was flawed, I debugged the precise position in both versions by manually setting the distance into the level and executing the routine to generate the screen x coordinates from the raw data. Both routines output identical values, so that wasn't where the problem resided.

After much debugging and some head scratching, I realised the subtle difference was due to the CPU interleaving. For my port, I run the main CPU for a full tick, run the road CPU for a full tick and then call the vertical interrupt code. However, on the original game both CPUs run in parallel. (MAME simulates this with some rough CPU interleaving). This means the road x values read by the main CPU, which are previously generated by the road CPU can be subtlely different. The difference depends on the precise number of cycles used by the code path of the road CPU.

There is no point in simulating this behaviour as it would massively complicate the codebase. It makes no visual difference, as the AI logic still behaves identically and the Ferrari crashes at the same points in each stage. I would suspect that the hardware differs from MAME again as a result of this but I haven't verified this theory. (Whether the difference is noticeable to the naked eye is another matter). The Saturn port, perfect in many respects, also differs in this area as a result of the timing differences.

Verifying this may have been overkill, but accuracy is important to me. In this case, the difference is thankfully inconsequential. I'm now moving on to a couple of other bug fixes I've identified, which will be tricky to track down!

No comments: