Tuesday 28 October 2014

To Emulate or Simulate: That is the question

I got my introduction into emulators from an old friend I've known since high-school. A gifted programmer, even back in the day before I got sick he had a much better grasp of low level programming.

He wrote an emulator for the NES which got me inspired to write an emulator for the Hack platform which after learning allot got me wanting to program a gameboy emulator.

His emulator is written like a piece of art. But I remember that it made me wonder. Is it really an emulator?

It's a very old discussion and something to consider before you start writing your own emulator (or simulator?) for any platform.

Let me (try to) explain the difference between emulation and simulation.


Simulation

The dictionary tells us simulation is:
"The representation of the behavior or characteristics of one system through the use of another system, especially a computer program designed for the purpose."
I imagine it as mimicking something so completely to the extend that it (almost) can't be distinguish from the original. It behaves exactly as the original in every sense of the word. Like it's been literally cloned in digital way.

A good example of this is the Visual 6502 emulator written in Javascript.  It's clearly a simulator because it doesn't simulate the processor itself but rather the transistors the processor is composed of. Like a human being simulated by it's individual molecules.

It will behave exactly, including bugs and undocumented opcodes, as the original physical processor.

So you might be led to believe that simulation is the only way to go. And well, for very specific use cases that might be true. But it has a huge downside, it's as slow as it can be.

Basically, taking the example of the virtual 6502. You more or less have to compute the state of all 3510 transistors within 1 microsecond to (only) run the cpu at 1mhz. Which boils down to 28.5 picoseconds per transistor state.

To put that into perspective, a 5ghz processor (do they even exist?) runs every instruction at about 200 picoseconds. We'd need almost 10x that power to run something that's 5000x slower. So it's far from efficient. I'm only barely exaggerating here. You can do things to make it more efficient.

Al-tho it might not be very efficient, you won't find anything as accurate.

Emulation

The dictionary tells us emulation is:
"The effort or desire to equal or excel others."
I imagine it like some kids I knew back in school. Emulating the other kids when it came to clothing and music preference to "fit in". They weren't clones of the popular kids, they only emulated them enough to be considered part of the group. Like a cat emulating a lion.

With the emulator I wrote for the Hack platform I could have build it as a simulator. The course gives you everything you need to know to build it from simple nand gates. But this would be very slow.

So I chose to write an emulator that executes one cpu instruction at a time. The lowest abstraction therefor aren't transistors, but instructions. Instead of having to compute thousands of transistors, you only need to do what the opcode says and keep an internal state from one instruction to the next. Add, subtract load a value, etc...

On an Intel 330m it can run 2mhz with absolutely no problems whatsoever. It's not exactly what the physical processor would be, but for all intents and purposes it works and behaves exactly the same.

But there's a catch!

In the hack platform and imho the gameboy this will work quite fine with few exceptions for which you can still write special cases. But that isn't always the case.

In real electronics there might be bus-conflicts and there might be an electrical pattern to determine which device wins the conflict that you are unaware of. There might be bugs in the physical processor or systems that programmers have used allot and depended on. Yes, we programmers did "stupid" things like that.

Implementing a textbook emulator following the hardware documentation for that processor or system as a whole might result in something that doesn't (quite) work. The weirdness doesn't stop there.

So how strange as this might sound. You really need to emulate the hardware bugs and bus conflicts if your working on a system that uses them allot. Like imho a NES. You might write special cases for them depending on which game is loading or something like that.

So emulation might not be very accurate (generally speaking), but it is as efficient and fast as you can get it.

Hybrid?

So simulating something is as accurate as can be, but emulating something is way more efficient. But those are just the extremes. Depending on your goals you might want something in between.

Like instead of transistors you could emulate at the half-cycle level. Emulating every state the processor and it's pins goes through. But that raises the philosophical question.

When does simulation stop and emulation begin?

If you use just-in-time-recompilation of original game code to run it on the host system. Are you simulating or emulating it? Or is that something different all together?

Both terms get thrown and mixed around allot and I guess that's fine. Perfection might be a balance of those two schools of thought.

Final Thoughts

In my gameboy project I've decided to emulate at the machine cycle level. Which equals four full
clock cycles. So it would run at 1mhz to emulate the physical processor running at 4mhz.

That's quite some understatement because timing is a whole separate story best told another time. So for now I hope I've just ignited a spark to inspire some thinking.

Will you write a simulator or an emulator? Maybe something which combines both approaches? Where do you think the boundary between the two exists. Is there a boundary or are they essentially the same?

Whatever your thinking, please don't let your head explode and have fun doing what you do.

Remember, the best way to write something is to start writing it. Worst case scenario:

You'll be rewriting it all, because you learned a better way to do it.

No comments:

Post a Comment