Reviving a 19 Year Old Gameboy Emulator

From Nick Faro's Homepage
Revision as of 17:51, 4 April 2019 by Nick (talk | contribs)
Jump to navigation Jump to search

Back in 2014 I was messing around with the idea of converting Gameboy .GBS soundtracks into Amiga .MOD files for a game I was doing. If you don't know what a .GBS file is, it's basically just a Gameboy ROM with z80 code but with the graphics routines and gameplay stripped out, so it's just the sound driver and music data, so in order to play it back you essentially have to emulate the full Gameboy processor and sound chip. At the time I was sort of infatuated with FreePascal and Lazarus, and wanted to find a Gameboy emulator written in Pascal that I could maybe yank the CPU and sound code from.

Somehow after scavenging over a bunch of old forum posts, I found (apparently) the only Gameboy emulator written in Pascal, ever: UGE. It was written by a guy named Christian Hackbart and released in 2000, and the only available download was from a mirror on Zophar's Domain. I started it up, loaded a ROM, was met with some ear-piercing noise, and then the emulator crashed. I canned the project pretty shortly after and that was pretty much that.

Fast-forward 5 years and I had the idea for another project centered around the Gameboy's sound system, and was compelled to go dig up the old code again and maybe see if I could fix it-- after all, it might be a good learning exercise to fix this thing up, and I kinda like the idea of an old abandoned piece of software rising from the ashes. So I dug in and tried to find out why this bad boy is flipping its graphics upside down, belching out horrible sound, running insanely fast, and crashing.

Fixing the speed

By a stroke of luck, I figured out that the reason the emulator was crashing: the sound emulation. If you untick the sound box in the menu, it stops running the sound code and it can be played for more than 5 seconds before blowing chunks. It still runs insanely fast and the grahpics are upside down though. I tackled the speed issue first. That should be as simple as just throwing in a spinloop to waste time and lock it to 60fps or whatever.

It looks like there was an attempt at this already in the code, using the Win32 QueryPerformanceCounter API, called RealSpeedEmulation. Unfortunately it calls QueryPerformanceCounter somehow completely wrong, passing in a member of a record rather than a pointer to that record... No idea why. I just ditched RealSpeedEmulation and did what GameLad does, which is just spin for a period of time until we need more cycles to be emulated.

Bam! Already it's almost playable, and the sound isn't causing crashes. I think it was crashing before because the extreme speed of the emulation was causing a sound buffer overrun or something.

Fixing the graphics

The emulator actually does render the screen right-side-up when using DirectDraw, but I can't record that with OBS for some reason. It renders flipped graphics when drawing with GDI-- let's fix that. In dib_out.pas I changed biheight := 144; to biheight := -144; and....

Nice. We've eliminated the