Gameboy Color Boot ROM
Abstract:
NOTE: This abstract is almost identical to the Super Gameboy one for obvious reasons.
A while back I began work on my FPGABoy project (a complete clone of the original GameBoy as a system-on-a-chip implementation on FPGA.) I have mostly completed the project since then (most GB original games run almost flawlessly on FPGABoy) with just a few minor things left to be done, including bug fixes and completing the sound core. Anyway, this page is not about FPGABoy; it is about hacking actual GameBoy’s and dumping their boot ROMs!
There was great news in the GB scene a short while ago, when Neviksti from CherryRom forums announced that he had been able to extract the BIOS image from the original GameBoy by decapping the chip, staining the ROM, and using a really powerful microscope to individually resolve and read out each bit one by one.
There are many other variants of the GameBoy however, namely the GameBoy Pocket, the Super GameBoy, and the GameBoy Color, all whose boot ROM images have had not been dumped. My goal is to dump these remaining boot ROMs electrically (no chip decapping or microscopes.) Almost a week ago, I managed to dump the Super Gameboy’s boot ROM by using a well-timed clock glitch. The Gameboy Color proved itself considerably more challenging and it took me several days before I finally managed to get it to fork over its precious boot ROM data! This just leaves the Gameboy Pocket, Super Gameboy 2, and the really rare Gameboy Light. Donations for the cause of science anyone? Shoot me an e-mail.
Technical Description (how I convinced the GBC to give me its bootrom)
On the Super Gameboy, I did not have a game cartridge I was willing to butcher so I soldered all the ROM bus wires from the FPGA directly to the cartridge connector of the SGB PCB itself. Realizing that this would be a huge pain if I wanted to switch the setup to a different Gameboy system, I did things differently this time around. I got a new Gameboy Color as well as some game cartridges from an eBay auction so I had some spare parts. I took apart one of the cartridges which just had a ROM chip and a memory banking controller (MBC) chip on it and desoldered both chips from it. I then used a multimeter to find which pads went to which pins on the cartridge header and soldered my wires there. Now I can just plug in the cartridge to the GBC (see photos below) and that leaves very few wires which need to be soldered to the actual mainboard of the GBC itself!
After spending quite a while transferring my address/data bus lines from the Super Gameboy to the game cartridge, I now had to prepare the victim GBC. I removed the 8.338MHz crystal and soldered a short twisted pair (ground+signal) of wires to the XIN pad on one end and to an FPGA output on the other end.
I also discovered that the GBC has two main voltages (besides the various weird voltages required for running the LCD): 3.3V and 5V. It seems like the GBC CPU uses the 5V just for I/O handling/driving and its core logic runs at 3.3V. I found the tiny 3.3V regulator chip (U6) and desoldered that also. I then ganged up two FPGA outputs (each output can easily source up to 16mA on this Spartan 3E) and directly fed the 3.3v supply from the FPGA (NOTE: Do not try this at home! It’s a bad idea to power something using I/O’s in general, but I noticed that the 3.3V rail draws almost no current so it would not be damaging my FPGA in this case.)
Now that everything was prepared, it was time to force the GBC to give me its boot code! First off, I ran through a few normal boots (sending a normal clock rate, and keeping VCC3 at a nominal 3.3V) and logged all activity on the address and data lines. Fortunately, just like the Super Gameboy, the same 3 things I noted hold true:
1. Almost all areas in the memory map that the SGB accesses appear on these external address lines (!), except for VRAM (different bus) and accesses to the 0×0000 to 0×0100 region (since it is mapped to the internal boot ROM.) This means that I not only see accesses to the external WRAM/ROM, but also to the FFxx registers and internal RAM regions!
2. The data lines always have FF on them when accessing a region which is not external WRAM or external ROM. That’s a bit unfortunate.
3. The last thing that goes on the address lines before my usercode at address 0×0100 executes is an access to location 0xFF50. This is known from the dump of the original GameBoy bootrom to be the register which locks out the bootrom forever (until the GB is power cycled or reset) once something is written to it.
The only difference is that the external RAM on the GBC is now on a separate physical address/data bus so I only see the address of RAM accesses on the cartridge (external ROM) bus instead of the data as well. That’s OK, I don’t really plan on using external RAM for anything anyway.
On to the fun stuff! I tried doing the same thing I did last time (with the Super Gameboy) by counting clock cycles until the ld ($ff00+50),a instruction and speeding up the clock by a lot temporarily, but unfortunately since the GBC was designed in a much newer design process, it was easily able to take any clock rate I sent at it for a short duration. The whole system even ran fine at 100MHz (!) in the boot ROM. It seems like the system uses at least a bit of dynamic logic, however, as I noticed that if I pause the clock for long enough and start it up again weird glitches start to happen. Time to give the GBC the worst time of its life at the right point! I hacked up my VHDL code so that right before the write to 0xFF50, it stops the clock and kills the 3.3V supply for a few seconds. I did not remove any of the bypass caps on the mainboard for the 3.3V rail and it seems like a few seconds are actually required for the internal logic to discharge appreciably (anything less and the system continues running just fine afterward.) So in summary, this is what happens:
- Send clock cycles at normal rate until right before 0xFF50 lockout instruction.
- Stop clock and drop 3.3V rail to 0 for a few seconds.
- Pull up 3.3V back to nominal voltage and start normal clock rate again.
Now, the VDD and dynamic clock glitching are causing a ton of random things inside the GBC CPU to happen. If we get lucky, it will flip enough bits such that execution will end up somewhere in the middle of the external ROM area before the boot ROM can lock itself out and without locking up. There is a lot more entropy in this kind of glitching than what I was able to do with the Super Gameboy (which glitched that specific opcode and worked every single boot). Thus, to leave a bit less to chance, I made the FPGA return NOP instructions everywhere except for my boot ROM readout code, and a JP 0100 (the location of my readout code in the external ROM) at 0x7ffe-0x7fff (the top of the ROM area.) This ensures that if when I return the GBC to normal operating conditions it falls through to the middle of external ROM somewhere, it will execute a bunch of NOP’s and then hit my jump back to a known location where I have the custom code which can read out the whole memory map (thereby dumping the boot ROM.) Knowing that the GBC boot ROM was bigger than just 256 bytes, I was not sure which areas were mapped to external ROM and which were to the internal boot ROM, but I knew that the header area (0×0100 through 0×0150) *must* have been mapped to external ROM since the boot ROM needs to read and check the Nintendo logo data. Thus I decided to locate my dumper code at 0×0100, which means that I need to return logo data from my FPGA ROM emulator to the GBC the first few times so that the boot ROM can verify it and not lock up, and then after the logo/header checks are done I need to start returning my dumper code data for accesses to the 0×0100 to 0×0150 region. This is the code I used to dump out the whole memory map:
This piece of code will endlessly read the whole memory map (0×0000 to 0xffff) and write it to address 0xA1xx where xx is the actual data read. I am tracing all accesses to the address/data bus (and 0xAxxx region is mapped to the external cartridge bus), so my PC code afterwards finds any writes to 0xA1xx and stores whatever xx is as the value for that location of the memory map.
After a few unsuccessful boots, it finally worked! As expected, the GBC got completely messed up and the code execution jumped to a random spot in the middle of ROM. It fell through all of my NOPs, reached my JMP 0100, and then started executing my code. I then post-parsed the huge trace file on the PC, and extracted the dump of the whole memory map. To my delight, the whole GBC boot ROM was sitting right there, mapped from 0×0000 to 0x00ff and from 0×0200 to 0x08ff! External ROM is thus mapped from 0×0100 to 0x01ff and 0×0900 to 0x7fff.
Photos of the GBC Setup (just be glad your GBC does not look like this!)
More photos here: http://www.its.caltech.edu/~costis/cgb_hack/pics
Downloads (yeah, what you’re really looking for!)
Gameboy Color Boot ROM (~3KB)
NOTE: The boot ROM is mapped in the GB address space from 0×0000 to 0x00FF and from 0×0200 to 0x08FF. In the binary file above, I have filled the space from 0×0100 to 0x01FF with 00′s which is where the external ROM data normally would be (from the cartridge header.) Hope that’s clear.
Also, Randy Mongenel (Duo) has worked very hard the past few days to reverse engineer the boot ROM and provide a well commented disassembly. It is still a work-in-progress, but he is almost done. You can download the WIP commented disassembly here!
Questions? Doubts? E-mail me at: costisNOSPAM@fpgb.org (remove NOSPAM before sending.)
Copyright 2009. Costis Sideris.
As usual, here comes the disclaimer:
I, Costis Sideris, have no affiliation with Nintendo Co, Ltd. Nintendo, ‘GameBoy’, ‘Super GameBoy’ and ‘GameBoy Color’ are all trademarks of Nintendo Co, Ltd. used without permission. I am also not responsible for anything you will or will not do with any information acquired from this website.