An NES emulator written in Go
github.com
github.com
It's awesome how the Gameboy kept me entertained for hundreds and hundreds of hours as a kid. -- Here I am over a decade later, and debugging my Gameboy [emulator] has kept me up into the wee hours of the night. (On more than one occasion, I might add.)
---
Funny thing is I was actually going to write a NES emulator. On new-years day I decided I really wanted to write an emulator that could play the original MOTHER.
After a little bit of cursory research: the Gameboy hardware seemed a tad more approachable. To be honest that's not terribly surprising: obviously to fit a game console in such a small package (for the time) you had to make a lot of sacrifices.
This walkthrough[1] writing a Gameboy emulator in Javascript was very helpful in seeing how an emulator should be structured. -- Though the full source is available: the actual tutorial is more of a guideline that introduces you to the hardware and structure of the emulator. It often shows code-snippets instead of working code.
The Gameboy CPU Manual[2] and OP code chart[3] have been invaluable tools. In my experience: I spent most of my time flipping between the opcode chart and my CPU implementation.
As a tip: lots of the CPU instructions do the same thing w/ different register pairs. There is huge potential for code reuse here. In Rust I achieved it with macros, though.
Lastly: the "Pan Docs"[4] are more or less the same thing as the CPU Manual, but in a slightly more readable format.
Also there[5] are some test ROMs[6] that you can use for debugging. I'm trying to find a good way to verify their results using Rust's unit testing.
`opus5.gb`[6] is a nice way to test the graphics subsystem; it's also a good "first ROM" to run because it has no additional ROM or RAM in the cartridge. In other-words: you don't need to implement the memory bank controllers to get it working.
---
And a little bit of friendly advice: _always_ keep debugging in the back of your mind. I usually resort to "printf debugging" but that really doesn't work inside a loop that's supposed to be ticking at 4.19MHz! :)
I accidentally filled up my disk once already; I forgot I had redirected STDERR to a file and it was pretty-printing registers after every tick. Yikes!
Good luck! It really is a fun little machine.
[1]: http://imrannazar.com/GameBoy-Emulation-in-JavaScript
[2]: http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
[3]: http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
[4]: http://problemkaputt.de/pandocs.htm
Thanks for the tip about the CPU instructions. I did notice that, but when looking through the Javascript code there was a one to one relationship with opcodes to instructions. Wasn't sure why the person went that way, maybe because it was easier? Either way I will keep that in mind and try to do code reuse!
Test ROMs are amazing! I have been playing around with a few ROMs I have and they all seem very complicated. This should make it easier to determine if I'm on the right track or not.
With the little code I have written, 90% of it is Printf to the screen to see what is going on :).
I do want to share with you this other tutorial that I found [1]. It is similar to the Javascript one, but it goes into way more detail on some parts.
Thanks very much for all the help! I have a lot of reading to do this weekend!
[1]: https://realboyemulator.wordpress.com/2013/01/01/the-nintend...
It also inspired me to build an interactive debugger that understands the Gameboy memory map. It's _pretty sweet_ when you can dump the 32x32 tile-map as a nice grid of tile offsets.
I'll think about cleaning them up and publishing them once I get the source up. I just get uneasy about publishing stuff like this. It just never feels like my prose [or my code] is "good enough" for the world to see.
I want to keep it all tucked away: so no one will make fun of my primitive debugger, or how I use hardtabs for indentation![1]
[1]: The Rust style guide dictates the opposite. They can pry the tab key from my cold dead pinky!
I never grew up! I still play my old GameBoy Color when I go on long trips. I know there are many emulators out there for these old systems, but I want to know how they work and figured if I'm still playing with one, let's make one!
Niels, if you happen to read this, fix your RSS feed so we can follow your future progress more easily! :)
https://github.com/hkhalsa/helloworld
I haven't added audio support yet, and it isn't very go-gettable (yet). But! the code is reasonably well commented, and I have played through much of Super Mario with it.
http://web.textfiles.com/games/nestech.txt is probably the best overview about what's going on in the NES, though it's inaccurate in some places.
http://wiki.nesdev.com/w/index.php/Nesdev_Wiki is a great site with far more information about the NES than you'll need to write an emulator.
Ctrl-Space, Alt/Meta-W, Ctrl-Y
y, p
I thought the Gameboy was odd enough with it's 'echo' of WRAM. (Which isn't even a complete mirror; it stops partway through WRAM#1.)
Reading the NES memory map though it gets quite silly! There's a mirror ($2008-$3FFF) that repeats a set of 8 registers ($2000-2007) _every 8 bytes._
Was this simply a matter of having more address space than physical memory? Or were these mirrors actually useful when programming these consoles?
---
I thought it might have to do w/ different addressing modes; perhaps you could save some bytes by just storing offsets or something. But that makes no sense in the context of the Gameboy. Many of the z80's extended instructions are gone; the only "interesting" addressing mode is a handful of instructions which treat an 8-bit address as an offset from $FF00.
Consider that GB WRAM mirror, where C000 = E000 all the way up to DDFF = FDFF. Let's look at these numbers in binary:
C000 = 1100 0000 0000 0000
E000 = 1110 0000 0000 0000
DDFF = 1101 1101 1111 1111
FDFF = 1111 1101 1111 1111
If you notice, that third most significant bit is the only difference - and this is true the entire way through the mirror. Because that address line wasn't needed to access WRAM, it was probably never even wired to it - so on access the value of it is simply ignored.3-player Bomberman 2 was also a big hit
Source: I've known the guy since he was thirteen.
Nope
- OS X: Just Go, Git, and XCode (this project doesn't use freetype).
- Windows: Just Go, Git, and MinGW.
- Linux: Apt can install all dependencies (installation instructions list more than are actually needed -- sorry).
And then you get a _single binary_ that runs on the system without the installation of any additional libraries. All libraries used are included by default on any modern OS.
Failed to feed audio to OpenAL fast enough; resynching...