8 ms·
Learn how to write an emulator
- z3phyr 8y agoImplementing 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.
- huntertwo 8y agoI want to second this. I did CHIP-8 two weeks ago and it’s good for getting your feet wet. I’m gonna finish it up with super chip-48, and then move to Gameboy. The progression feels natural and it’s fun and rewarding.
- SaulOfTheJungle 8y agoHow do I get started? What resources do you suggest?
- fernly 8y agoWhen 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 8y agoI 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.
- lin0tune 8y agohttp://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?
- deleted 8y ago[deleted]
- teraflop 8y agoWhat's wrong with that? If you're writing code for pedagogical purposes, it doesn't necessarily need to be as concise as possible.
- monocasa 8y agoIn fact, in my firmware writing style, I tend to separate MMIO accesses from mutation to make it clear when those bus accesses occur.
- simias 8y agoI 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 8y agoAbsolutely. 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.
- planteen 8y agoYes and read/write barriers are also sometimes necessary, to prevent re-ordering by the compiler and processor.
- alok-g 8y ago>> 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.
- aap_ 8y agoIndeed. Software emulation is fun and all but real hardware works differently.
- planteen 8y agoYeah, for sure, especially for more modern CPU features like caches and OOO that are very difficult to emulate in software. But you can't share hardware designs (e.g., FPGA bitstreams) like you can software binaries or software source code. A hardware design will require a specific FPGA, board, and probably even a particular version of the synthesis tools if you want to build from source.
- aap_ 8y agoYou can still share the source code. Just requires some assembly then.
- aphistic 8y agoDo you have any recommendations for tools for this?
- paulsmith 8y agoNot tools per se, but check out the Bitwise education project, where Per Vognsen is coding an entire hardware and software stack from scratch, live on stream. https://github.com/pervognsen/bitwise https://github.com/pervognsen/bitwise
- 8y ago
- kstenerud 8y agoA 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 8y agoIf 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).
- kodablah 8y agoI 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.
- masklinn 8y agoIIRC Dolphin as a JIT. In fact I think it has separate JITs for the CPU and GPU.
- kodablah 8y agoI think rpcs3 does too. What I need to understand (and probably only takes a small bit of digging on my part) is how they keep from having, say, my extremely high powered computer go way faster than what was expected in the original. Surely there's a scheduler involved, but does it install OS-like hooks? Does it sleep on the threads? Meh, I should just go read.
- drb91 8y agoModern games (say, since the playstation 2 generation) tend to rely on clocks to compute animations. This is most obvious today when consoles often get several different clockspeeds across their release lifetime--my current xbox one is faster than my original xbox one by a tangible amount. It's also necessary when different parts of a 3d scene will render at different rates--you don't want to be able to slow the animation down by looking at something complex.
- zeta0134 8y agoActually emulating the CPU, even with a JIT, isn't as much of a performance drain as you'd think. The performance elephant is synchronization. If the CPU and the GPU aren't running at exactly the same speed as they were on original hardware, then timing is different from what a game might expect, and that can introduce untold bugs. Real games on the console didn't have to worry about timing variances, so the emulator can't have them, but that means it needs to do a whole ton of extra work to make sure the various hardware bits are all running more or less in sync with each other.
- sehugg 8y agoThe 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.
- planteen 8y agoWow, that is really neat!
- jackhack 8y agoThat'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 8y agoHope you like the books! I'll have some basic Apple ][ emulation available on the site soon.
- stuckinarut 8y ago> Subtracting the CPU emulator If you're subtracting the CPU emulator what is the point of doing any of this?
- roblabla 8y agoI think the parent's point was meant to illustrate that there is very little boilerplate necessary beyond the CPU emulation (which is, arguably, the fun bit). On more modern systems, the CPU is only a tiny bit of the equation. You might have to emulate the graphics pipeline, the audio processor, the input mechanism, etc... This makes the process of writing an emulator more tenuous, as those are not nearly as straightforward to implement, and might be badly documented. If you look at the really modern platforms (like the Switch or 3DS), CPU emulation is barely 20% of the work.
- amelius 8y agoDoes this address optimizations, as seen in LLVM and JIT compilers?
- simias 8y agoAs 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 8y ago> 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?
- monocasa 8y ago> However, if emulating e.g. ARM on i86 (or vice versa), I guess that recompiling optimizations may be necessary to keep things efficient. Depends on the ARM in question and how dependent on cycle accuracy the rest of the system is. Anything more than ~100MHz you pretty much need to JIT, but a surprising number of systems don't reach that. So like a DS is generally interpreted, but a 3DS is generally JITed. > Wondering: does VirtualBox use such approach? VirtualBox uses a combo approach depending on the host. 32 bit host uses a very simple JIT that runs ring 0 and runs all guest code in ring 3. The JIT hides itself using the segment registers. It's mainly to emulate the few instructions that don't fulfill Popek & Goldberg on x86 (ie. instructions that act different in ring 0 vs ring 3, but don't trap). It'll also play with the page tables to know when self modification occurs. 64 bit host is way easier. Pretty much just relying on hardware virtualization, and interpreting a single instruction here and there when you get a trap out of hardware virtualization into the hypervisor.
- wpdev_63 8y agotoo bad it's in objective-c :/
- metasaval 8y agoIt does go into Objective-C later, but it starts with C. You can see that if you go to Disassembler Pt 1.
- apple4ever 8y agoThat’s the best part!!! Love me some Objective-C
- jweather 8y agoIf you like writing small emulators, try the Synacor challenge and/or ICFP 2006. Extremely challenging puzzles, and both start with writing a simple emulator.
- bahmboo 8y agoThis 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 8y agoI 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 :)
- 13mtfb 8y agoIf 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/