Introducing 4-e: Super Mario Advance 4 e-Cards without an e-Reader

Super Mario Advance 4 is more than Super Mario Bros. 3.

When this final game of the Super Mario Advance series launched, it of course had Bros. 3 for its main draw. But it also went all-in on Nintendo’s e-Reader, a special cartridge with an optical scanner that could read specially-encoded data on cards that Nintendo distributed.

Nintendo published over a hundred cards for Advance 4. These e-Cards were power-ups, switches that changed the game (like adding Super Mario Bros. 2 turnips to pull up and toss at enemies), gameplay demos showing secrets, and even whole new levels that could be scanned in.

Well. In Japan, at least. North America got less than half that card count, and a handful could only be scored from Wal-Mart. Europe got zilch.

Several years later, Nintendo put Advance 4 on the Virtual Console for the Wii U, and with it, loaded all thirty-eight card levels right into the game. Which is awesome—many of these, North American players had never had the chance to play. All of them, for European players. This same affordance is available on the Nintendo Switch Online service right now.

However, even with the levels added, these are still missing all the demos, power-ups and switches—both those we had in North America and those we never got. Even if they were available, getting hold of those cards is no small feat. Plus, there’s also the possibility of bringing in all-new community levels, too, built using community tools like Smaghetti.

But if you don’t have the cards (or the game on cartridge or an e-Reader or even a second Game Boy Advance), or you’re doing something brand-new, what can you do?

There’s long been the option to try to print your own e-Cards. I actually have a few I successfully managed to do some years back, on a high-DPI laser printer I no longer have access to. Most printers will completely fail at the fine dots needed, though. The error correction on the e-Reader can only take you so far.

Many folks have been taking the route of patching levels into saves for the game. Smaghetti does this; you can then relatively easily play it on an emulator. But playing it on real hardware is a chore, and really isn’t very close to the original experience—and it‘ll never support demos, power-ups, or switches.

e-Piphany

I got to thinking after reading a blog post about a new homebrew link cable library —what if we took the e-Reader itself out of the equation? Printing and the optical scanner were weak links. What if we fooled Advance 4 into thinking it was talking to an e-Reader that someone was using to scan cards, but in reality, we were just transmitting the data?

I’ve been poking at this for a few months, on and off, assembling information and tools. I’ve finally been making great progress just this week, culminating in the oh-my-god-it-works moment the other night and the release I’m putting out today.

4-e is Game Boy Advance homebrew that is built with devkitPro, yielding a “4-e.gba” ROM. You then grab the decoded version of an e-Reader card (a 2,112-byte-long ".bin" file), stick it in a GBFS archive, append that archive to the ROM, and it’s ready to go.

Now, run that ROM, hook up the link cable, and get Advance 4 ready to scan. Once you start the scan, 4-e takes over, acting as an e-Reader and transmitting the data to the game. That’s it!

Reverse e-Ngineering

It seems like such a small thing, but it was really the product of many hours of experimentation and learning.

To start with, I probably never could have got this project off the ground without the fantastic mGBA emulator. I set up its multiplayer mode with a ROM of my Advance 4 cartridge, a ROM of my e-Reader, and used its e-Reader scanning support to “scan” a ”.raw” version of one of my e-Cards.

mGBA could then log everything that took place over the emulated serial line between the two emulated Game Boy Advances. It looked like this:

[DEBUG] GBA Serial I/O: Lockstep 0: Transfer initiated
[DEBUG] GBA Serial I/O: Lockstep 1: SIOMLT_SEND <- FBFB
[DEBUG] GBA Serial I/O: Lockstep 0: SIOCNT <- 608B
[DEBUG] GBA Serial I/O: Lockstep 0: Transfer initiated
[DEBUG] GBA Serial I/O: Lockstep 0: SIOMLT_SEND <- FBFB
[DEBUG] GBA Serial I/O: Lockstep 1: SIOMLT_SEND <- FBFB
[DEBUG] GBA Serial I/O: Lockstep 0: SIOCNT <- 608B
[DEBUG] GBA Serial I/O: Lockstep 0: Transfer initiated
[DEBUG] GBA Serial I/O: Lockstep 0: SIOMLT_SEND <- FBFB
[DEBUG] GBA Serial I/O: Lockstep 1: SIOMLT_SEND <- FBFB
[DEBUG] GBA Serial I/O: Lockstep 0: SIOCNT <- 608B
[DEBUG] GBA Serial I/O: Lockstep 0: Transfer initiated
[DEBUG] GBA Serial I/O: Lockstep 1: SIOMLT_SEND <- 5841
[DEBUG] GBA Serial I/O: Lockstep 0: SIOCNT <- 608B
[DEBUG] GBA Serial I/O: Lockstep 0: Transfer initiated
[DEBUG] GBA Serial I/O: Lockstep 0: SIOMLT_SEND <- 5841
[DEBUG] GBA Serial I/O: Lockstep 1: SIOMLT_SEND <- 5841
[DEBUG] GBA Serial I/O: Lockstep 0: SIOCNT <- 608B
[DEBUG] GBA Serial I/O: Lockstep 0: Transfer initiated
[DEBUG] GBA Serial I/O: Lockstep 0: SIOMLT_SEND <- 5841
[DEBUG] GBA Serial I/O: Lockstep 1: SIOMLT_SEND <- 5841

Having run a few cards through, I took copious notes, and then headed over to devkitPro to try to figure out, well, how to make Game Boy Advance software. I’d done Nintendo DS before—how hard could this be, right? (Spoiler: there’s a bit to learn.)

Serial I/O on the Game Boy Advance is very interesting, turns out. I thought maybe I could save myself some effort by leveraging gba-link-connection, the library I’d discovered earlier. Carefully studying my notes and mGBA logs, I built up a program that did what looked like about the same thing.

And it sort of worked in the emulator. Some of the time. And not at all on real hardware. But I was already starting to learn a lot, especially comparing what was going on in mGBA with my software with GBATEK’s excellent documentation. I’m grateful to gba-link-connection for giving me a foot in the door with this stuff.

I decided I’d go a level deeper and tried to use gba-link-connection’s “LinkRawCable” support instead of the standard “LinkCable” (which is honestly great, but really designed, I think, to work with other games using the same library). Sadly, “Raw” didn’t help me in this scenario.

So I finally cracked my knuckles and started replacing all the calls to gba-link-connection with my own code, studying every line of what was going on with the real e-Reader ROM’s logs. The biggest breakthrough I made here was making sure that I only ever sent data in sync with the game, which manages timing on the serial line. This solved the reliability problem.

The issue pile was dwindling, but not yet zero. Of course, there were lots of undocumented magic numbers being sent back and forth across the line. It looked like all but one were the same every time. I reasoned that one was a checksum of the card I was sending, but I just could not figure out how that checksum was calculated. I was even briefly entertaining the idea of trying to get a disassembler running to watch the e-Reader do that calculation.

Then I had a chat with a coworker who suggested a simple idea: why don’t you change one of the cards you’re testing with, just a little bit, and see how that number changes?

Easier said than done, to be honest—I can change a byte in the decoded card, re-encode it with nedcenc, but then the e-Reader ROM would reject it. I eventually found a tool called sma4_regcon, designed for changing the region of cards, that also had the side effect of regenerating the card checksum. I tweaked it a bit to unconditionally do so, and now I had a card that would scan.

I'd changed a padding byte by 1, and I noticed the mystery field's high byte moving by the same amount. Turns out it was a simple checksum; I'd just got hung up on byte order when trying to calculate it off-system. Rolling the two-byte data packets as they passed into a 16-bit checksum worked.

Finally, I noticed that what I thought was another magic value that changed based on card type, simply because it didn't move between power-up cards, was not enough to make Advance 4 happy, I stared at the differences between cards for awhile… and finally realized, while trying to go to sleep, that the second magic value was just the most significant two bytes of the aforementioned checksum, which was actually 32 bits.

That's what I get for staying up too late.

e-Nhancements to come

4-e in its current form works, but there of course is more that I could, and would like to, do with it.

The big one: right now, 4-e only sends the first object (i.e. e-Card bin) out of the GBFS file. I can generate lots of 4-e ROMs with each e-Card I might want to store on my Pocket (4-e runs great with spiritualized1997's GBA core), but it'd be even better if one ROM had a picker for which e-Card to send. (Update: this is done!)

It'd also be nice to have a point-and-click webpage to bundle up the ROM and e-Cards. The GBFS tools aren't hard to use, but you need to have them, of course.

I mentioned Smaghetti before—Smaghetti seems to only export save files. I'd like to figure out a nice way to get e-Cards out of it that folks could then publish themselves.

Beyond that, I could stand to add some things like timeout handling and the like—right now, if anything unexpected happens on the serial line, 4-e will just sit there, ever hopeful that continuing to do what it's doing will make something good happen. (Update: you can, at least, now cancel most operations.)

Nonetheless, I'm really proud of where this is, and I'm thrilled to release it. I hope folks find it cool and useful, and it contributes to the preservation of the experience of one of my all-time favorite games.


You'll only receive email when they publish something new.

More from Mattie B
All posts