
Learn how to write an emulator - dreampeppers99
http://www.emulator101.com/
======
sehugg
The Space Invaders (Midway 8080) platform described here is really easy to
emulate; it's just a 1-bit frame buffer hooked up to a CPU. Subtracting the
CPU emulator, my implementation on
[http://8bitworkshop.com/](http://8bitworkshop.com/) takes less than 200 lines
of code. One of the easiest with which to get started.

~~~
jackhack
That's a real gem!

I also started out on the Apple ][, writing my own versions of the games I saw
in the arcades (donkey kong, pacman, joust, etc).

My kids are old enough to be curious about how games are actually built, and
we've had fun building an adventure game in basic, and a version of asteroids
in C. We had planned to build something this summer, so this book of yours is
an ideal next step which we can work through. I think they'll really get a
kick out of seeing how it all goes together. (okay, okay, I admit it.
Nostalgia hit me hard and I just want an excuse to fire up my old Apple ][
again.) Regardless, I just hit "order" on Amazon.

~~~
sehugg
Hope you like the books! I'll have some basic Apple ][ emulation available on
the site soon.

------
kstenerud
A long time ago, I wrote a 68000 emulator in C to replace MAME's x86 assembler
core. After months and months of poring through my old Amiga programming books
and the Motorola manual, I still remember clearly that moment where I fired up
the emulator, and actually SAW the title screen of Rastan Saga come up after
the game booted from my core. Truly a magical experience...

After that, I doubled down and wrote a g65816 emulator for it (that's the CPU
the SNES and Apple IIgs used). Emulator writing is almost a zen-like
experience.

~~~
matthewwiese
If you happen to remember, which of those Amiga books was the most useful to
you?

At the moment (well, for _years_ really) I have been in a 6502 binge, but want
to get into m68k programming as well (and the Amiga ecosystem specifically).

------
alok-g
>> Want to really learn how a CPU works? Writing an emulator is the best way
to learn about it.

The best way to learn how a CPU works would be to write a CPU! I.e., write HDL
code for it and test in a hardware simulator.

I have designed a miniature application-specific processor, a compiler* and
IDE for it, a disassembler, and an emulator too.

* To be more precise, I hacked a compiler for it using C# .net compiler.

~~~
aphistic
Do you have any recommendations for tools for this?

~~~
alok-g
I had developed using professional IC design tools (specifically Modelsim and
Xilinx) for the processor. However, free tools are available like
[http://iverilog.icarus.com/](http://iverilog.icarus.com/)

The actual processor was implemented on a Xilinx FPGA, and it was about 2K
lines of HDL code, carrying about 25 application-specific instructions which I
had designed also.

For the compiler, disassembler, IDE, emulator, I created in C# and .NET.

While I did not use these, there are also ASIPs:
[https://en.m.wikipedia.org/wiki/Application-
specific_instruc...](https://en.m.wikipedia.org/wiki/Application-
specific_instruction_set_processor)

------
z3phyr
Implementing an emulator is similar to writing an interpreter and imo more
rewarding in certain cases.

Start with CHIP-8, it's the gateway drug to others.

~~~
SaulOfTheJungle
How do I get started? What resources do you suggest?

~~~
fernly
When I did my CHIP-8 [1] I collected a lot of background info and links, which
you can find in the "History" and "Sources" topics of the readme.md there.

[1]
[https://github.com/tallforasmurf/CHIP8IDE](https://github.com/tallforasmurf/CHIP8IDE)

------
grawprog
I wanted to learn SNES assembly once, but I found the actual limitations of
the SNES frustrating, do I made my own 24-bit virtual machine and basic
assembly language. I was getting confused with how to implement interrupts so
I took a look at an open source gameboy emulator....turns out without really
knowing what I was doing I had written an emulator.

That was really awesome to work on though. I probably learned more working on
that than anything else. It was the first time I really felt like I understood
entirely how a computer actually works.

------
kodablah
I want to learn how to write an emulator that is not an interpreter and still
keep it timing accurate (even if not completely cycle accurate). I haven't
dug, but some of the ones for modern machines seem to compile instead of
interpret yet I don't know how they handle timing.

~~~
saganus
What is the difference, in this context, between timing-accurate and cycle-
accurate?

~~~
monocasa
Timing accurate: this instruction takes four cycles, so do the work, and
increase master clock by four.

Cycle accurate: this instruction takes four cycles, so this push the address
to the multiplexed A/D bus. Next cycle read the data. etc.

So more fast forwarding in timing vs cycle accurate. Typically timing accurate
doesn't implment things like wait states injected by other peripherals
accessing the main bus either.

------
13mtfb
If you're interested in processor emulation, here's a really cool one done in
HDL for the pdp 11/70:
[https://wfjm.github.io/home/w11/](https://wfjm.github.io/home/w11/)

------
bahmboo
This is pretty much about writing a cpu emulator. A system emulator is much
more complex even as far back as a gameboy or Sega genesis. I think there is
still great value in writing your own cpu emulator as described in the
article.

~~~
plandis
I used this website for information for both a Chip8 emulator and later an NES
emulator (which uses a 6502). The PPU for the NES was definitely more of a
struggle but Emulator101 is still a great resource even if you want to go on
for emulating other chips / peripherals :)

------
jweather
If you like writing small emulators, try the Synacor challenge and/or ICFP
2006. Extremely challenging puzzles, and both start with writing a simple
emulator.

------
amelius
Does this address optimizations, as seen in LLVM and JIT compilers?

~~~
simias
As far as I can tell it does not feature a recompiler, only an interpreter.
Emulator recompilers are very tricky to get right. Since you're working
directly with machine code instead of nice bytecode you generally need a bunch
of heuristics to avoid optimizing something that shouldn't be optimized
(register access being an obvious candidate). Furthermore machine code
(especially for older consoles) tend to use self-modification liberally so you
need to figure out the right heuristic to invalidate your recompiled cache
when the machine code is modified.

In general for these very old systems (anything 8bit these days I'd say, and
even 16bits if you're only targeting the desktop) a recompiler is probably
more trouble than it's worth.

~~~
amelius
> In general for these very old systems (anything 8bit these days I'd say, and
> even 16bits if you're only targeting the desktop) a recompiler is probably
> more trouble than it's worth.

I guess that's also because modern CPUs can easily handle very old systems,
which were relatively slow, and hence software written for it had to be
efficient.

However, if emulating e.g. ARM on i86 (or vice versa), I guess that
recompiling optimizations may be necessary to keep things efficient. Of course
emulating JITted code can be a pain because of self-modifying code. Wondering:
does VirtualBox use such approach?

~~~
simias
>I guess that's also because modern CPUs can easily handle very old systems,
which were relatively slow, and hence software written for it had to be
efficient.

It's that but it's actually worse than that: power aside, one hertz for one
hertz, modern systems are generally much more recompiler-friendly than a
GameBoy or Atari. The reason is that modern software is written using high
level abstractions, you have well defined firmware interfaces, self-modifying
code has become the exception instead of the rule etc... That lets you make
simplifying assumptions that can speed things up greatly. For instance "I
don't have to worry about self modifying code unless I encounter a call to the
firmware's flush_cache method". That's better than "I need to be careful with
every write to memory because it might potentially write to code instead of
data or registers".

Back in the days it wasn't rare to find timing loops that required cycle-
accurate emulation, for instance because the drawing code expected that the
delay between the interruption until a certain instruction was executed was
precisely _n_ cycles. I doubt many people do that on a PS4, actually I would
be surprised if you could make something like that work between all the
various hardware revisions and firmware updates.

So older hardware generally requires the emulator to be a lot more strict
which often means that you end up with a comparatively slow recompiler. Given
the complexity of a recompiler compared to a simple interpreter it's simply
not worth it anymore for these old systems.

------
wpdev_63
too bad it's in objective-c :/

~~~
metasaval
It does go into Objective-C later, but it starts with C. You can see that if
you go to Disassembler Pt 1.

------
lin0tune
[http://www.emulator101.com/logical-
operations.html](http://www.emulator101.com/logical-operations.html)

    
    
       /* Example 2: turn on one LED on the control panel */    
       char * LED_pointer = (char *) 0x2089;    
       char led = *LED_pointer;    
       led = led | 0x40; //set LED controlled by bit 6    
       *LED_pointer = led;
    

Really?

~~~
teraflop
What's wrong with that? If you're writing code for pedagogical purposes, it
doesn't necessarily need to be as concise as possible.

~~~
simias
I know some people who object to one-line read-modify-write of hardware
registers, the idea being that glancing at the code the non-atomicity of the
operation might be lost. I also generally don't use raw volatile pointers
directly when dealing with hardware registers, too easy to forget a "volatile"
somewhere and have the code behave erratically. I always use tiny
read32/write32 wrappers instead.

~~~
kstenerud
Absolutely. Modern compilers are trivially able to inline such operations, so
there's no reason not to make your intentions and separation of operations
crystal clear. After all, you're going to read the code a lot more often than
you'll write it.

