Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

I recommend learning an assembly language to get the basic knowledge you need here. If you are interested in for example the super nintnedo, you would try to learn 65816-assembly, which is the assembly language for the processor used by that console. To get started, you could start reading here: http://en.wikibooks.org/wiki/Super_NES_Programming. Similar resources exist for other consoles. I also recommend getting an emulator with debugging features, such as Geiger's debugging snes9x, which will let you step through the execution of the game, dump what it is doing, inspect memory, etc. While none of that is directly relevant for writing a console emulator, it will give you some of the background you are looking for.

To be honest, though, if C looks totally alien to you, it might be best to learn some of that before trying assembly. C is much more abstract than assembly, but will still give you a grounding in many of the important concepts, most importantly pointers.

But basically, what an emulator does is to step through the machine code of a game, executing it instruction by instruction. A console is a rather complicated beast, with several processors and co-processors and associated hardware working in unison. So you should probably start out with a simpler emulator which emulates only the CPU, and ignores the rest. The reason why learning assembly is so useful for this is that assembly has a 1:1 translation with the machine code the emulator is supposed to handle.

If, as you say, you know nothing about hardware then writing an emulator is not going to be easy. It is probably more impartant to understand the basic functionality of hardware than to know any particular programming language.

I can recommend Noam Nisan and Shimon Schocken's book The Elements of Computing Systems and its associated internet resources ( http://www.nand2tetris.org/ ). The book takes you from simple nand gates to building a functional computer then on to writing an assembler, a compiler and an operating system and finally the game of Tetris. At each level you can "build your own" or use the web available answers to build on for the next level.

First and foremost programming an emulator requires knowledge from multiple domains. The two big areas you need a firm grasp in are computer architectures and a programming language of your choice. Creating an emulator is not a good idea if you have no programming experience at all. With that being said, you can create an emulator in any language you wish as long as you know it well!

In order to understand how systems work it's advised you brush up on computer architecture. I recommend reading a good book on the subject such as Computer Architecture: A Quantitative Approach which is a pretty common book for most architecture classes.

Once you have a working (basic) knowledge of how systems operate (CPU, memory, registers, instruction sets etc) you can attempt to emulate a system of your choice. At this stage I recommend digging around for as much information as you can about the system of your choice. Zophar.net has a nice collection of technical documentation on a number of video game consoles.

Once you have a working knowledge of the system you wish to emulate I suggest writing code to read the ROM files and extract the file contents (instructions in particular). The next step is emulating the architecture's CPU and writing handlers for each instruction. I test the CPU by running the CPU on the actual instructions I load from the ROM. After you have a good number of instructions implemented you can begin to implement other subsystems such as the graphics and event/interrupt systems. The final system I usually implement is sound.

(Shameless plug) I am writing about all of this more in a book called Emulation - Step by Step which I hope to publish within a couple months. I have yet to see another book on the subject and it's shameful because it's such an interesting topic!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top