What's new

Emulation

remmy

reenignE
I've been sitting here going over the forum and can't believe how many "How do I write an emulator?" threads I've seen. Not saying that this is bad. It's a good thing that there are a lot of ambitious people out there looking to further their knowledge about other architectures. A nice sticky topic would be great to have for people looking for this information. Letting them know that understanding a programming language isn't really what emulation is about. It's understanding the hardware. Being able to emulate another processor requires (for some... you others are just brilliant :p ) weeks, if not months of reading and absorbing. You can be an excellent programmer and have absolutely no idea how to emulate a system.

Some things that I would recommend:

Go to the library and check out some books on microprocessors. They can be very informative.

Once you have a good understanding of how said processor works, try some books on assembly. You'll find that converting between x86 and other architectures isn't that hard of a task once you have a good understanding of the language.

Let's face it. C/C++ are the definitive languages for emulation programming. Once again, turn to books if you do not know the language or simply need a refresher.

The internet is huge. You can find just about anything you desire. When all else fails, use it.

Look at (do not steal) other people's source code. You'll find that many emulators are documented or written cleanly enough so that understanding what each function does is a snap.

As it has been said here many times: Start simple. You have seen how easily beginners have gone from never touching C/C++, to writing a chip8 emulator.

After you have exhausted all of these resources, ask questions. A lot of the people here really enjoy helping other people learn knew things. I personally haven't seen a more helpful group of people willing to go (sometimes almost painfully) indepth to help someone out.

I for one know the benefits of having someone around that understands things that I don't, or just having them there to give you a new perspective on something that you do understand. Many, many optimizations in my code have come from my friend Paul who always seems to be able to spot those little things that I miss.

It's easy to say that you are going to create a X, but doing it is the hard part. It's in no way impossible; however you must be willing to learn and not just give up like so many others do.
 

zenogais

New member
Couldn't agree more, but the part about emulator code being well documented and understandable is open to debate :p
 

bcrew1375

New member
That's true, zenogais. I have not seen an emulator yet with readable code. I'm making my Gameboy emulator very clean, so people can understand what everything does. remmy, where are these "well documented" emulators you speak of? :p
 
OP
remmy

remmy

reenignE
One of my favorites is Nestopia. It's not commented all too well, but you can easily make out what is going on. I have a habit of describing what each function of my code is doing even if it's perfectly obvious. Comes in handy when you lay down a project and pick it up some time later.
 

zenogais

New member
I tend to document all my code using doxygen, its simple to do and it makes sure people have no excuse for not understanding your code. Not to mention you can add some neat code samples and stuff into the documentation.
 

BGNG

New member
I hereby provide to you THE RULES OF THUMB for Emulation:
1) Understand the concept of Assembly. It's the same for any processor; it's just the instructions which vary.
2) Know your number systems. The three biggies are Decimal, Binary and Hexadecimal.
3) Emulator programs should run themselves. Executing opcodes directly with as little programming overhead as possible will make clean code and a fast emulator.

Boy. That was tough. Three things to keep in mind.

The exact programming language used to write an emulator isn't so much important as to what the programmer is able to do with it. One perfect example is the way C/C++ supports variable and function pointers while variations of BASIC do not. For that reason, and that reason alone, is why I'm coding an emulator in C++ instead of Visual Basic. That, and C++ tends to compile smaller and faster than VB. If another variation of BASIC were to come out, however, which openly supported all kinds of pointers, I expect a lot of pretty good emulators to come out of it. (Even if I have to do so myself, bwahahaha)
__________

FUNCTION POINTERS AND EMULATION

While there are some very advanced techniques for making speedy emulators, perhaps the pinnacle combination of ease and efficiency is the Function Pointer. A good (and I speak from experience) technique is to make one function for each instruction, then store the pointers to each function in memory (perhaps an array, but variable pointers will be faster).

Most older processors isolated instruction opcodes to whole bytes. When it comes time to execute an instruction, one byte is read to determine which instruction to execute, then the next byte or two was the data to use in the instruction. If any given byte value references the pointer of the corresponding function to handle it, then the function can be called directly using the value of the byte; which eliminates the need for conditional checks with If/Else blocks or a Switch (Select) statement.

For newer processors, like the ARM processors in Game Boy Advance and Nintendo DS, the exact instruction specified by the opcode is somewhat mixed in with the data. Some bits in some instructions correspond to opcode designation; where those same bits may be actual data in another instruction. Typically, the kind of opcode you'll be dealing with can be determined by looking at the first few bits of the instruction. By having two sets of functions with pointer arrays: Execution and Opcode Decoding, you can make the program run itself with still only two steps and no If/Else/Switch stuff. The Opcode Decoding function can expand upon the opcode after the first few bits are read (which is faster than applying a series of bit masks), then the Execution function can be called later.
__________

I tried to keep it short, so it isn't very thorough. If you would like me to expand on that concept, say so.

Also, I am aware that there's a big fad going around for emulators called Dynamic Recompilation, which as I understand, translates the code from the ROM directly to code executable by the native system processor, where the code is called upon its necessary usage. If this is not correct, then correct me... because I see ways that doing that can make an emulator VERY inaccurate.
 

Hacktarux

Emulator Developer
Moderator
A well written dynarec isn't inaccurate. On an interpreter there are a few basics steps for each opcodes: decoding the instruction, executing the instruction and to do that you have some conditionnal branches or function calls and the main emulation loop. The goal of a dynarec is to only execute the instructions : instruction decoding is only done once when it's possible (ie: there's no self modifying code) and there's no loop or branches or function calls between the opcodes because it's compiled into native code. Doing only that doesn't make it inaccurate if it's correctly done. This description is very simplified....
 

BGNG

New member
Thank you for posting those links, zenogais. They'll keep this thread uncluttered with the specifics of those things and allow for other noteworthy comments in regards to general emulation.

When I say an emulator should run itself, I'm referring to the programming going directly from reading of ROM data to execution of the opcodes. If blocks and Switch statements are the so-called "programming overhead," as they are additional code and cycles not necessary for the program to operate correctly. Use of Function Pointers allows the program to immediately call the required function based solely on the value of the bits read from the ROM; and thusly runs itself.

And I thank both of you for clarification of Dynamic Recompilation. I was under the impression that it's little more than "reassembly" of instructions from the ROM to the native system, but I can now see that doing so wouldn't exactly be dynamic, now would it?

What I had in mind for breaking an emulator was what I like to call Executive Overlapping, where bytes used for some instructions could theoretically be other instructions if read from a different offset or if read in a different processing mode. An example of this almost-impossible scenario would be THUMB instructions being read from bytes that were previously executed as ARM instructions.
__________

The following is an excerpt of a technical document I'm authoring:

EXECUTIVE LIMITATION BY MEANS OF VBLANK

If you're not programming an emulator on a PC, it may be difficult to time the emulation so that the virtual CPU doesn't execute too much code in the alloted amount of time. Since it is not practical to emulate a faster processor than the machine with the emulator, some kind of limitation is needed to keep the emulator from emulating too much code; more than would be executed on the real processor of the emulated machine.

The perfect real-time limiter for this is the video refresh rate of the system running the emulator. Most videogame systems run at a constant 60hz for video; that is, exactly one frame is displayed every 1/60 of a second. In order to limit the emulator to the amount of code executable by the emulated processor, divide the number of cycles per second the emulated processor can handle by the video refresh rate of the machine running the emulator and wait for VBlank every time that number is reached. This is typically done as "Emulated_CPU_Speed / 60." Count the number of cycles each instruction takes, and when the maximum number of cycles for the emulated processor is reached, simply stop emulating until VBlank occurs on the system running the emulator. Afterwards, continue emulation as normal.

There may be other operations the emulator needs to complete before the actual framebuffer is displayed on the system running the emulator, so don't stop the emulator altogether; simply disallow it from executing code until VBlank occurs.

If you are programming an emulator on a PC, then force your video rate to be at a constant 60 hz and continue emulation after each frame is drawn to the output device.
 

Top