I’ve spent a lot of time (and money) over the last several months indulging my fetish for vintage video games, especially NES and Game Boy titles. And while nothing beats playing these games on the original consoles, emulators offer many features that are hard to live without, such as increased game play speed (seriously Prof. Oak, we get it), instant save states, and cheat codes. A ROM dumper could be a bridge between consoles and emulators, allowing me to play most of the game on the console, then transfer my saved game to an emulator if I get stuck and need to cheat. Yea, yea, I’m not a purist. So shoot me. Furthermore, I can build up a library of legally-acquired game backups to keep on my Everdrive for a long plane ride. In the process, I can learn a lot about the Game Boy hardware, and Z80 systems in general, which will shallow the learning curve if I start developing my own games and programs in the future.
My basic requirements are a device that can interface with Game Boy and Game Boy Advance cartridges and perform the following functions:
- Interface with Linux application
- Dump cartridge ROM (cart->PC)
- Dump cartridge RAM (save states)
- Overwrite cartridge RAM (PC->cart)
My design is inspired by the GB Cart Flasher system I found here (about halfway down the page), which includes schematics, a board layout, firmware binaries, and C++/Qt source code for a PC interface program (gbcflsh). I referenced the harware schematics to get a feel for how I wanted to design my device, but the firmware was of no use without source code. The code for gbcflsh, however, I modified to suit my requirements, and have been using to capture the data from the Romboy.
Overall, the design is simple. A program running on a PC sends a command to a microcontroller, which executes the command by interfacing with the GB or GBA cart. The microcontroller needs to be capable of bi-directional communication with the PC, as well as contain routines for accessing all of the ROM and RAM available on the game cart.
I’ve been a huge fan of the AVR ATMega series for several years now, so using one at the core of the Romboy was pretty much a given. I have quite a few ATMega328P chips on hand, so initially designed around that. However, it quickly became obvious that the 328P didn’t have sufficient I/O to interface with the cart without using shift registers. While this wouldn’t be too hard to do, it adds complexity to the firmware and hardware and slows down read/write operations significantly. It would be much easier to connect the cart’s 8-bit data bus and 16-bit address bus (16-bit/24-bit for GBA) directly to the I/O ports on the AVR. After a little research, I settled on the ATMega32A. It has enough I/O ports to directly interface with 24 data and address lines, as well as four control lines (read, write, chip select, and reset). That leaves just enough for a UART, a status LED, and a mode select pin (for choosing between GB and GBA).
For simplicity, I elected to directly tie the micro’s pins to the cart’s pins, as the two are voltage-compatible. In a future hardware revision, I may buffer the lines or add optoisolators to protect both the cart and the micro, but for now it’s fine as-is. So all I really need is a cartridge connector. As I’m unwilling to sacrifice a real Game Boy cart connector to the cause, I ordered a few of these, which took several weeks to arrive. Because they’re designed only to accept GBA carts, I had to snap off the tabs on the sides to fit the GB carts. It’s an easy fix. The hard part was soldering signal wires directly to those pins, due to their fine pitch. Any future revisions I build will be on a custom PCB, thus eliminating that difficulty.
For simplicity, I designed around the FTDI232RL for UART<->USB communication, just like in the GB Cart Flasher project. To make things even easier, I didn’t even build this in to my prototype- I just installed a six-pin header to use with one of my FTDI cables. A future revision might replace the FTDI chip with a USB-capable AVR, which would reduce the board component count and vastly improve communication speed. But this would require significantly increasing the complexity of the firmware (as in the Statscreen project) and potentially writing a custom Linux driver. I don’t have that kind of skill just yet.
Given that I’ll be using the AVR’s UART port for communication, I need to select a crystal oscillator that will support a standard baud rate. And since I must assume a system voltage of 3.3V (see below), I am limited to a maximum system clock of 10.67 MHz, since With this restriction, the highest clock that will yield a standard UART baud is 7.3728 MHz. The best I can do is 460800 baud, but I’ve found that 230400 is much more reliable. This is actually pretty slow. It takes several minutes to dump a 1MB Game Boy ROM, which means GBA games are going to take a full lunar cycle.
Because Game Boy carts operate at 5V and GB Advance carts operate at 3.3V, I will need two separate Vcc lines. Fortunately, both the FTDI chip and the AVR run just fine at both voltages, so I decided to include a DPDT switch to power the entire system at one voltage or another, rather than design special circuitry to step the voltage up or down to accommodate the other type of cart. There’s a good chance that one type of cart will run just fine at both voltages, but I decided not to risk it. Because USB provides a clean 5V supply, I only need to include a 3.3V regulator and a few filtering capacitors. The only caveat is that the status LED resistor is based on 5V, so it will be a bit dimmer at 3.3V. Oh well. This is also the reason for the 3.3V restriction on the crystal oscillator.
An interrupt routine in the firmware populates a receive buffer with bytes from the serial bus. Once that buffer has been filled to the preset packet size, the interrupt sets a flag called
data_avail. Once that flag is set, the main program loop enters a set of functions that parse the packet and determine the nature of the request from the host computer. A packet can represent a request for cartridge header information, a dump of ROM or RAM, writing the RAM, etc. Once the request has been identified, the firmware calls a function to execute the request. Once complete, the function returns, and the program loop flushes the rx buffer. Any bytes received by the interrupt routine before the buffer is flushed are ignored.
Before any read/write operations can be performed, the cartridge header must be read. This is how the firmware determines, among other things, the amount of ROM and RAM and type of memory bank controller. This information is stored in a struct called
cart_header_t, and must be populated before any of the read/write functions are called.
Host software: gbcflsh
While I’m grateful to have found the gbcflsh software, I quickly discovered that the code was a tangled, abhorrent mess. But all the major pieces were already in place, which means I only had to reverse-engineer it’s communication protocol with the ROM dumper. It turns out to be pretty simple. Fixed packet sizes, no encryption, no whitening. Only a simple CRC performed on the packets, the algorithm for which I was able to literally copy and paste from gbcflsh in to my AVR firmware. Other than that, I just had to dig through the code and see how it was building outgoing packets and parsing incoming packets. A few hours’ work and I was in business. Nice.
I’m getting ahead of myself.
I first had to get the software to compile. It includes a makefile, which is awesome, but it kept throwing compiler errors at me. Turns out that all I had to do was add
#include <stdio.h> to a handful of source files, and it was up and running.
The software includes functionality to read the ROM (and write the flash if it’s a flashcart) and read/write/erase the RAM. There are combo boxes on the left side of the app that allow you to set the MBC, ROM, and RAM size. I don’t really understand what the point of this is, since all that information is included in the cart’s header. So I reworked the software to populate this information automatically after the header has been read by the Romboy. Furthermore, only the relevant read/write functions are enabled in the software, based on the capabilities of the cart. As of now, the modified software does everything I want it to. But the code is ugly. It was ugly when I found it, and all the sloppy debugging statements I added only make things worse. But I’ve also made efforts to remove unnecessary, repetitious code and simplify its architecture. It’s a work in progress, but it gets the job done.
Expanded game compatibilty
As I write this (August 18, 2015), I still consider the Romboy to be in the early stages of development. Currently, it is able to read the ROM and read/write the RAM from carts only with MBCs 1, 3, and 5, as this represents the extent of GB games that I own. Furthermore, MBC1 carts with more than 512kB of ROM may not download properly, due to the non-availability of banks 0x20, 0x40, and 0x60. The firmware should automatically skip these banks, but I do not believe the gbcflsh software accounts for this. It shouldn’t be too hard to implement, but I don’t have any such games with which to test. So I’ll be on the lookout for additional MBC1 and MBC2 games. Any other game type may not be feasible, as there seems to be a dearth of information on the Web about them.
Game Boy Advance carts
The major missing piece is, of course, Game Boy Advance cart compatibility. The Romboy has been designed with this feature in mind, but the current prototype does not yet have the 3.3V circuitry included on it. There’s plenty of room on the board to add it, though. According to shinyquagsire23’s blog post, however, the GBA carts will work just fine at 5V. Nevertheless, I don’t want to chance frying my games, so I’ll just add the 3.3V regulator before I start mucking around.
The major difficulty in adding GBA functionality will be from a lack of reference material on the Web. The shinyquagsire23 blog post is the only project I have found so far. And while it looks pretty straightforward to dump the ROM (no MBC to fuss with!), I didn’t see any information about reading or writing the RAM. I’ll also have to rework gbcflsh to work with GBA carts.
Printed circuit board and case
I suspect I’ll probably lose interest in this project before I make it this far, especially since this can involve a significant investment. But if I end up dumping a bunch of games, or perhaps writing my own Game Boy applications, it might be worth the time and money. On the other hand, I may want to try and sell the Romboy once the project has matured and stabilized. Then again, I doubt there’s a huge market for dev tools on 20+ year-old hardware. :P
The following Web pages were of tremendous help while developing Romboy.
- Reiner Ziegler’s colorful site, which hosts links to the gbcflsh and GB Cart Flasher project source files.
- An Arduino-based dumper on Inside Gadgets Alex Iannuzzi did a great job documenting his implementation, which was a huge help while designing my firmware.
- Gameboy Development Wiki has a great breakdown of the different types of memory bank controllers.
- WormFood’s AVR Baud Rate Calculator is incredibly handy.