I’ve been trying to simulate a Tama-Go figure ROM for awhile, so I can write my own Tamagotchi games, and hopefully find some way to dump the main ROM of a Tamagotchi. I tried to obtain compatible flash memory, but GeneralPlus (the maker of the low-power SPI ROM used in Tamagotchi figures) does not deal in small quantities, and the closest match I could find wasn’t close enough to work properly. I also tried using SPI on my Arduino, but it wasn’t quite fast enough to keep up with the Tamagotchi, and the resistor on pin 13 caused problems detecting SPI clock. Finally, I ordered a ChipKit Uno32, a faster, PIC-based Arduino clone.
This board is fast enough to keep up with the Tama-Go, and uses jumpers for SPI slave mode, so the resistor on pin13 is avoided.
There are still some speed limitations when using this board– having it query external memory or devices, or even do a lot of math to determine the return value for an SPI command is out of the question, but it can return a reasonable number values that are included in code. It’s not possible to simulate the entire Tamagotchi ROM at once this way, as there’s not enough memory, but I hope I can simulate it bit-by-bit in order to determine the format (although I suspect I might run out of memory when doing the game portion).
I started by simulating a figure being attached to the Tamagotchi. When this happens, the Tamagotchi displays an object in the background (for example, a wardrobe that clothes come out of, if it’s a figure that’s a ‘clothing store’, or a table if the figure’s a ‘restaurant’). It also plays a song, and displays a screen with the figure character dancing if this is the first time this particular figure has been attached to the Tamagotchi.
Using the SPI functionality of the ChipKit Uno, I determined what memory address the Tamagotchi queries when a figure is first attached, and then modified the code to return the value at that memory address (which I got from the figure ROM dump I did awhile ago) after the first SPI command. Once this value was correct, the Tamagotchi started to make a second query, so I made the code return the value at that address after the second query, and so on. Unfortunately, a lot of this had to be done manually, although I used Python to generate some of the code.
Currently, I can simulate up to the background image being loaded. Details of the simulation are below
|1||Read 0×000001||0xaa 0×55 0×08||If this value is not exactly as shown (as far as I can tell), no more queries are received|
|2||Read 0×000011||0xaa 0×55||Returning these values has no visible effect, but Tamagotchi makes an additional query|
|3||Read 0×000013||0×03 0×03 0×03 0×00 0×00 0×10 0×03||Returning these values cause the figure to be visibly ‘detected’. If this is the first time it’s been detected, the new figure song plays, and the background for the dancing character is shown, but no character (the Tamagotchi is probably trying to load it, but getting back zeros). If the figure has been attached before, the ‘smoke’ for when the background object is displayed appears, and the tone plays, but the device freezes before the wardrobe is displayed|
|4-13||Read 0×20-0×50||corresponding address values||Returning these values has no visible effect, but I suspect it is where the ‘dancing character’ is loaded (which isn’t actually displayed, because I’ve loaded this ‘figure’ before)|
|14||Read 0×000001||0xaa 0×55||A several second delay, probably checking that the figure is still attached|
|15||Read 0x0000CE||0x9a 0x2b 0×00||The first two values are clearly a pointer to the background image (I tested this by changing the value, and it attempted to read the new value + 0×10 next), not sure what the 0 is for|
|16||Read 0x002BAA||0×11 0×15||Image dimensions|
|17-||The image is read|
Next up is tampering with these values to see if I can cause any unexpected behavior.
The code for this is available here, and I’ve also uploaded a dissembler for two GeneralPlus instruction sets. You never know when you might need to disassemble a GeneralPlus binary, and it’s best to be prepared for these sort of things :).