How does one learn to program game console emulators (hardware knowledge specifically)?

ZimZim picture ZimZim · Oct 29, 2012 · Viewed 9.3k times · Source

I've asked a similar question before, about how to write an emulator, and when I saw the answers and looked up some open source gameboy emulators, I found that there was much more needed than an intermediate understanding of a "low level" language (i.e. C). What I actually want to know is, what do I need to know about HARDWARE to be able to program such an emulator. I'm closing in on being "pretty good" at Java, but that won't help me a lot. I've started learning C and I've come a long way now, but I'm interested in knowing what I have to study in hardware to be able to write such a console emulator.

The reason I'm asking this question is that I've been searching around the internet for books and sources on emulation, and whenever I come across an emulator tutorial, it's always like "you need a basic understanding of C to be able to follow this tutorial" and when I try to follow it I can't, simply because I don't know what the hell is being programmed. I've never known anything in the slightest about hardware. (my dad who struggles to connect his monitor to his PC probably knows more about it)

So my question is, what do I need to study (microprocessors, memory, etc?) and are there any good sources for this that can teach me about this stuff without me having to go to college for it or something (already doing software engineering)?

I apologize if this is not a real question, or not clear enough, or anything like that. I am just very interested in the subject.

Answer

Mario picture Mario · Oct 29, 2012

Think this might be more suitable to programmers.stackexchange.com, but anyway:

I wouldn't say you need any specific knowledge. Knowing how microprocessors and memory management work will help a lot as will assembler knowledge (because you're essentially writing an interpreter for assembler-like code). Assuming you already know how your target hardware works, all you essentially have to do is implement the following components (i.e. faking the real hardware and mimicing/emulating it's behaviour):

  • Simulate a CPU parsing and running the machine code.
  • Simulate the input components (transform things like keyboard, mouse or joystick input into "pin signals" accessible to the CPU).
  • Simulate the output components (transform image and audio data into something visible, e.g. show something on screen or generate sound like the real hardware components).
  • Simulate other components, like memory packs, built-in batteries, cartridges, extension chips, etc.

As a general advice, I'd say forget about writing any emulator for now. Instead start with something simple by trying to write your own byte code interpreter.

As an example, you could use a simple pseudo code sequence:

x = 5
y = 10
print(x + y)

Written in pseudo assembler, this could be something like this:

mov x, 5
mov y, 10
add x, y // to be honest, this is essentially x += y; not just x + y
prt x
end

Now replace all instructions with (code) numbers. All variables are replaced with numbers:

0x01 0x00 0x05
0x01 0x01 0x0a
0x02 0x00 0x01
0x03 0x00
0x00

This might look a bit odd, but I've kept above's order and line breaks. Note that I've used 0x01 for the first instruction rather than 0x00. This is just for convenience, so I'm able to use 0x00 for "NOOP/no operation" or as a terminator (as in this case). Now just remove line breaks and you end up with custom byte code essentially.

char code[] = {0x01, 0x00, 0x05, 0x01, 0x01, 0x0a, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00};

To run this code, you can write a simple "emulator". It just has a limited instruction set, but it will work. I actually didn't test this code, so keep in mind I might have screwed up at some point. It should however be enough to give you an idea on how/what to do. Note that in this example I don't split data memory and instruction memory. This would add more complexity not really required for now.

int pos = 0; // essentially being our "instruction pointer"
char registers[10];
while(code[pos]) { // still some instruction
    switch(code[pos++]) { // determine what to do and move the instruction pointer
    // 0x00 isn't handled here, as that's part of our loop already
    case 0x01: // mov(e)
        registers[code[pos++]] = code[pos++]; // read the value into the register
        break;
    case 0x02: // add
        registers[code[pos++]] += registers[code[pos++]];
        break;
    case 0x03: // prn
        printf("%d", registers[code[pos++]]);
        break;
    }
}

Once you understand what I did here, I'm pretty sure you should have an easier time to understand other sources as well. Oh, and a fun fact: If you're doing it for educational purposes and not just to write an efficient simulator, you could just start using Java. It will be less optimal and slower, but you can essentially do the same things, possibly even removing at least on hurdle on your way.

Just a quick note: In above's example you could have a second thread constantly writing the contents of registers[] on the screen. This way you could essentially emulate some video hardware (e.g. TV screen or LEDs).

If you're looking for more sources to read, I'd try to grab some simple processor and start learning assembler code. Pick a very simple architecture, if possible. The concepts are always the same, but things might get complicated with more and more instruction sets, address space virtualization, etc.