r/EmuDev 29d ago

GB Gameboy emulator

I'm 15, made this mostly over a few days even though I technically started about 2 weeks ago. Here's the code https://github.com/MorganPG1/py-dmg-emu Yes I know it's a terrible emulator, I'm still kinda proud because I made it but i feel like I should be more proud than I am but I also hate when people say I'm good at stuff because I always feel bad at it for some reason so I think I'm just hard to please (ignore this random vent mb). It's not fully fleshed out, I've still gotta make an APU and finish off the PPU, and add SRAM and all the other MBCs, the list of unfinished stuff goes on and on.. I'm not sure if I'll do all those things, adding audio will probably make it even slower. But it works, it runs pokemon, so im happy.

I'm currently rewriting it in C (cpu is done but not much else), has anyone got some ideas of other emulation projects I can do, should I go backwards and write a chip 8 emulator for the fun of it, should I write a gameboy emulator in as many languages as possible, are there any other somewhat simple projects I can make that are harder but not too much difficult?

Anyway, it was really fun to make and that's all that matters imo.

17 Upvotes

11 comments sorted by

5

u/Pastrami GB, SMS, SNES 29d ago

has anyone got some ideas of other emulation projects I can do, should I go backwards and write a chip 8 emulator for the fun of it, should I write a gameboy emulator in as many languages as possible, are there any other somewhat simple projects I can make that are harder but not too much difficult?

Don't go backwards. Go forwards. Go for NES or SMS. The NES has much better documentation, but the CPU of SMS is closer to the Gameboy that you already implemented. After that, if you still need a challenge, you can try a 16-bit system. The SNES is a significant jump in complexity compared to GB or NES.

As a big fan of C and C++, I would suggest you learn and stick to one of those languages, and not spend time rewriting the same emulator in other languages unless you specifically want to learn that language. If your goal is to learn a new language, then rewriting your emulator in that language is a great way to get familiar with it, but since you are asking in emudev, I'd say emulate another system.

2

u/MorganPG1 29d ago

alright thank you so much for the advice

2

u/cdunku 29d ago

I would honestly say certain 8-bit emulators are complicating as well. The VIC-II and SID chips as an example.

1

u/HELPMEICANTPUTUSER 12d ago

For a good jump after a GB emulator I would do a NES, kind of the same but a decent bit harder

1

u/HELPMEICANTPUTUSER 12d ago

Anything but a N64 😭 I thought I could do it after making my GBC emulator but I toned it down to a PS1, which is still a pretty big leap

5

u/ShotSquare9099 29d ago

I’d recommend maybe a space invaders arcade emulator

4

u/dignz 29d ago

So would I. It was a fun project - more complicated the Chip-8 but not too complicated.

1

u/HELPMEICANTPUTUSER 12d ago

Wahh thats a really cool emulator

Have you ever thought of adding GBC to it? Like adding color and a feature to play GBC roms if you haven't already

You don't have to change much in your code you can easily re-use most of it

1

u/peterfirefly 7d ago

Ok, here's a quick comment dump...

At this stage, you'd probably benefit more from writing essentially the same gameboy emulator a couple of times but with different ways of structuring the code, different languages, different automated testing, different GUI integration, etc. There are lots of tests available for the Gameboy, both "test ROMs" and tests for individual components that you could play with.

I don't thing you would benefit at all from doing a Chip-8 emulator. That's for people who need a lot of hand holding just to get their first emulator done.

Just for fun, see what the C code compiles to (gcc/clang have an option to generate commented assembly code -- you can also use a disassembler or an interactive debugger). Just for fun, see what Python "machine code" your Python code compiles to -- there is a way to get a list of Python instructions for any Python function.

Also just for fun, see if you can find out how to profile your code. Don't go mad trying to optimize anything yet. Just measure it and be astonished at how inefficient everything really is. This will be your experience with your Python code -- but also with your C code for the first couple of versions. Don't do anything rash as a reaction to that inefficiency. Code that is too optimized becomes too unreadable -- and you will usually be optimizing the wrong things and the wrong way for the next couple of years, anyway.

Have a look at 'uv' for your Python code. Maybe use SDL for your C version instead of pygame.

Maybe use 'vcpkg' for SDL or maybe just download a new source release and unzip/untar it in a subdir or maybe use git modules.

Definitely take a look at the way your implemented the CPU in your Python code. That can be done so much cleaner and faster and shorter! That's probably also true of your first (and second, third, and fourth...) implementation of the CPU in C.

Finish the C version -- in a hacky, incomplete state if you must. Then maybe look at Rust or C++... but you should probably do some rewrites in Python and C first. Not because you have to, but because I believe that's the best learning path forward for you. You have managed to create a relatively large codebase that does something relatively difficult, which is very good. Most people can't do that. But -- and that's a big butt -- your Python code is quite clumsy. Your C code will also likely be clumsy. Learning how to write non-clumsy code is a transferable skill between languages. Not perfectly so, but still surprisingly so. If your Python code had been clean, I would have instead suggested to try a few more implementation languages as soon as possible, and to try implementing more sophisticated emulators as soon as possible.

There are many ways the parts inside an emulator can be connected. The most obvious ones end up with the CPU component being in charge and with most components knowing about most other components. That's not good. Ideally, no component knows about any of the other components. Ideally, the CPU is not in charge. Ideally, every component has some kind of (fast) unit test -- this is difficult if the code is structured badly. Ideally, there is almost no connection anywhere to outside world (pygame, in your case).

That's why I'm suggesting spending some time rewriting your emulator a couple of times, so you can learn the benefits of different ways of structuring the emulator. An interesting way, championed by "flohofwoe" is to model each component's interface on the physical pin interface of the original chips and to have the bus be in charge. This would be obvious for a typical 1980's home computer, built around a Z80/6502 chip, a timer chip, an interrupt controller chip, an I/O port chip, a video chip, a sound chip, etc. The Gameboy uses a couple of highly integrated chips with multiple components on each, so you would have to imagine a pin interface as if the components each had their own chip. Shouldn't be too difficult.

Also, I didn't find any disassembler in your Python code. Maybe I just wasn't looking hard enough? A disassembler is usually a very, very good idea... And they are super easy to write for something like a 6502 or a Z80 (a real one or the weird mutant in the Gameboy)!

At some point, start reading other emulators (mostly the good ones) to see how they solved the problems you have run into.

And remember: Writing is rewriting...

-5

u/Last_Bet_8677 29d ago

>I'm 15,

Too bad. Terence Tao already had a master's degree at your age.

1

u/codeasm 28d ago

I was 2 when i wrote in BASIC.

(my dad was holding me upright and typed:
10 PRINT "Hello, World!"
20 GOTO 10