Saturday, August 05, 2006

Completed, at Last

As you'd probably noticed, the pics in the previous post are of the Bubble Bobble custom MCU.

Despite being one of the most popular games of all times, and having been in MAME for many years, the emulation of this game has never been perfect due to the lack of the original ROM for the MCU.

For some time, we had been using a 68705 program found in a bootleg board, believing it had been extracted from the original. However, monster behaviour was wrong and there were other problems, like the wrong behaviour of the clock item.

After some study of the program and of the game schematics, it became clear that the original MCU is not a 68705 at all (the pinout doesn't match) but looked more like a 68701.
The 68705 program had been written from scratch by the bootleggers using black box reverse engineering techniques, by running the original MCU and logging all its reads and writes from memory. Indeed, the 68705 program does a lot of reads from memory without doing anything with them--simply because the original MCU would read that memory and do some unknown action with it.

Eventually, the useless 68705 program was replaced by simulation code inside the emulator, which greatly improved the emulation accuracy. Monster behaviour was improved, the clock item behaviour fixed. However, there were still some unknown things, like how the randomisation of the EXTEND bubbles really worked.

At last, thanks to excellent work by Trinity, the original MCU ROM has been extracted. This required removing the cover from the chip, taking photographs of it under a microscope, and manually decoding the contents of the ROM bit by bit. The photo shown in the previous post confirms that it's in the 6801 class, not a 68701 however as it was conjectured, but a 6801U4.

With this ROM, we finally have the final piece of the puzzle for a 100% guaranteed perfect emulation.

Checking the original MCU program was very interesting. It was designed to provide many protection features that were eventually not used by the game, like:
  • process coin inputs and update the credit counter
  • handle the number of remaining lives for both players
  • handle the current round number
  • handle variable speed incrementing for four variables
  • return values from a 1280 bytes table of seemingly random data
The reasons why those features were not used are probably various. Some of them were probably awkward to use because they require to one one frame for the MCU to process the data, others weren't flexible enough like the coin input processing that wouldn't allow for coinage settings different from the ones hardcoded in the MCU (though versions of Bubble Bobble with different coinage settings don't seem to have been made anyway).

So, how close was the simulation to the real thing? Very close; "too good", actually. Let's see why.

The clock item behaviour was spot on, but off by one frame (the simulation made the counter expire one frame too late).

The EXTEND randomisation simply doesn't exist in the original MCU. While the simulation code used a RNG to provide truly random letters, the original MCU simply increases the counter every frame. This seriously affects the game, making the EXTEND letters predictable.
Since a new bubble enters the screen exactly 128 frames after the previous one, and the remainder of 128 / 6 is 2, this means that if you get consecutive letters each one will be 2 places after the previous one. So if you get 3 letters you can get either E, T, N or X, E, D. After that they will repeat. There are exceptions, though: if you create a new bubble in exactly the same frame when a new bubble should enter the screen, the bubble is delayed by one frame. So by timing the fire button exactly right you can change the bubble order. In theory you could get all 6 letters in a single level--let me know if you manage to do that! :)
Also, new bubbles will not appear if there are already 16 bubbles on the screen, so that will change the order as well.

The last, and most important, thing that the MCU does is compare the player coordinates with the monsters. The results are returned as flags indicating whether each coordinate is >, =, or <, and the absolute difference. This was done correctly in the simulation code, however there appears to be a bug in the original MCU. The code there attempts to check if the player collided with a moster and set a flag and indicate which monster in that case, but it just doesn't work. It would set the flag even if the player's Y coordinate matches one monster and the X coordinate matches a different monster!
This isn't much of a problem since the main program just ignores the flag--the collision detection is done correctly by the second Z80.
However, the MCU also completely stops processing the monster coordinates as soon as it finds a monster whose X coordinate is within 8 pixels of the player. So e.g. if you have a monster right above you three platforms up, and that monster is the first in the list, the other monsters could stop following you. This is a very subtle effect that's completely unnoticeable from what I can tell, though in theory it exists.

Thursday, August 03, 2006

Good News

What's inside this?




More on this later.