-
Exploring The Decompressed SRAM
07/30/2023 at 12:55 • 0 commentsThe general layout of the decompressed SRAM is as follows:
- 0x00000 to 0x057FF: Animation slides
0x05800 to 0x05FFF: Animation path and settings - 0x06000 to 0x0B7FF: Background image
- 0x0B800 to 0x0BA3F: Music track
- 0x0BA40 onward: Music settings
The music track and settings are structured as described by BoodaW at NesDev.
The SNES uses bitplanes to store images, and follows the same approach in saving a Mario Paint image. (The series of YouTube videos on Super NES Features by Retro Video Game Mechanics Explained is a good primer on how this works.) Mario Paint images have fifteen colours (plus transparency), so are stored as a 4 bit-per-pixel bitplane.
The colour pallette is as follows:
- 0x00: Transparency
- 0x01: Red
- 0x02: Orange
- 0x03: Yellow
- 0x04: Light Green
- 0x05: Dark Green
- 0x06: Cyan
- 0x07: Blue
- 0x08: Maroon
- 0x09: Brown
- 0x0A: Pink
- 0x0B: Purple
- 0x0C: White
- 0x0D: Black
- 0x0E: Dark Grey
- 0x0F: Light Grey
This order nearly matches the order of the colour selectors on-screen when using Mario Paint, but note that White is in a different location. (It is positioned right-most inside Mario Paint.)
The background image is generally known to have an area of 248x168 pixels. This is indeed the visible image, but the images is actually stored (in Save RAM and also in the SNES' Work RAM) as a 256x174 pixel image, with a four-pixel transparent border. This allows the image to be stored as a series of 8x8 tiles: 32 across, 22 down.
The transparent border allows the picture to be centred on the TV, while still using the SNES's native tile layout. This border is replaced with a black & grey frame in-game, which can turn red depending on the user's actions.
The animation frames are stored in another 256x174 pixel bitplane, at offset 0x0000. The same bitplane is used for 4, 6 and 9-frame animations: the bitplane is subdivided according to the number of frames being used.Individual frames can be addressed by selecting the appropriate tiles from the bitplane, and have their own 4 pixel transparent border surrounding each frame. There is some additional transparency at the edges of the bitplane when 6 or 9 animation frames are used, to keep each frame the same size. The 6-frame bitplane has eight transparent pixels on the left and right sides (instead of 4). This means there's a whole column of unused/transparent tiles on either side of the bitplane when using 6 frames. The 9-frame bitplane is likewise, but has an extra 8 pixels of transparency along the bottom (one whole row of tiles).Counting tiles from top-left, the relevant tiles for each size of animation frame is:
- Large (4 frames): (0,0) to (15,11), (16,0) to (31,10), (0,11) to (15,21), (16,11) to (31,21)
- Medium (6 frames): (1,0) to (10,10), (11,0) to (20,10), (21,0) to (30,10), (1,11) to (10,21), (11,11) to (20,21), (21,11) to (30,21)
- Small (9 frames): (1,0) to (10,6), (11,0) to (20,6), (21,0) to (30,6), (1,7) to (10,13) (11,7) to (20,13), (21,7) to (30,13), (1,14) to (10,20), (11,14) to (20,20), (21,14) to (30,20)
From 0x5800 to 0x5FFF, information is stored about displaying the animation frames on the background image.Animations can be set to display at a particular point, or along a given path, by drawing a path of pixels in Mario Paint. This information is stored from 0x5800 onwards; a maximum-length path occupies bytes up to 0x5FF1. Each path pixel appears to require three additional bytes (after an initial zero-byte). The number of path pixels is stored at location 0x5FFA.
Location 0x5FF8 indicates the layout/number of animation frames in use. 0 indicates four frames, 1 means six frames, and 2 means nine.
Location 0x5FFE stores the speed at which the animation can run, from speed one (0x000) to thirteen (0x0C00).
Location 0x5FFC seems to hold some data (often 0x0100), but its purpose isn't yet clear. There's no clear use for bytes 0x5FF2 to 0x5FF7.
I've yet to identify how the path pixels are encoded in memory. Drawing paths in an emulator and inspecting the decompressed memory hasn't yielded any results yet.
- 0x00000 to 0x057FF: Animation slides
-
Motivation and Initial Investigations
07/29/2023 at 21:53 • 1 commentA short while ago, I bought a copy of Mario Paint (plus SNES mouse) as a birthday gift for my budding young artist. I'd not played this title when I was young, so this was my first exposure to it too.
They had a play around with it, and having drawn their first artwork, they asked me to print it off for them. The explanation that it couldn't be printed off the TV, and the fact that only one picture could be saved, didn't cut the mustard.
I'd learned that the image was compressed and saved onto an SRAM chip inside the cartridge. Wiring up a microcontroller to read the contents of the SRAM chip (with a suitable connector for the cartridge) would be straight-forward, but the challenge lay in interpreting the compressed data and extracting the image.
Initial searches online turned up a partial disassembly of the Mario Paint ROM, which didn't include the portions for saving and loading images. I am passingly familiar with 6502 assembly (the little brother to the SNES' processor), but wading into a full ROM disassembly didn't appeal.
The music composer of Mario Paint (and the in-game music) has a bit of a cult following. B00daW collected some findings on reverse engineering the music composer on a NesDev forum thread. He credits HertzDevil for identifying the compression algorithm as a combination of LZ77 and Huffman encoding, and attached a Lua script to decompress and extract the music from an SRAM dump.
However...
Mario Paint saves both the image and music (and animations) when prompted by the user. If they are saved and compressed at the same time, it would be sensible to compress them together to maximise the compression ratio.
On running the Lua script on a sample .srm file, I was greeted with a 47kB output file, far larger than needed for the music alone. Using B00daW's notes I identified the region where the music was stored, leaving lots of space for the image to be hiding in. Armed with a SNES emulator and some spare time, I started creating images and searching the decompressed data with a hex editor to search for my simplistic works of art.