I've been working on and off on a Nintendo DS emulator 100% written in Go. You can have a look here: https://github.com/rasky/ndsemu/
It features both the 2D and the 3D engine (with a full software rasterizer with poly-fillers generated through go generate). It's highly concurrent (each graphic layer is drawn in a different goroutine and then mixed together). The ARM interpreter is also generated via go generate.
I think Go has great potential in this area. Some emulators (? PCSX2/Dolphin/...) are famously stuck with very few threads owing to the design of the underlying hardware, so anything that encourages extracting parallelism from within each subsystem could potentially be a major performance win.
Cycle-perfect emulators at least for typical 8- and 16-bit systems need to run each emulator subsystem (CPU, video, audio, ...) in lock-step for each clock cycle. Spreading those emulator systems over multiple threads would mean that the threads need to synchronize with each other after each step (which is just a few host CPU instructions long). It might be easier for more modern hardware where subsystems are much more decoupled from each other (and I guess with Moore's Law dead this is our only hope to emulate more modern hardware in the future).
That's true. In the case of Nintendo DS, I'm aligning doing line-based emulation; so I first serially emulate the two CPUs (I could in theory parallelize then, but I haven't properly design the emulator around this, so all memory-mapped callbacks are not concurrent safe), and then emulate the graphic subsystem for a single line, spreading the different layers across different goroutines.
This means that goroutines synchronize 263*60 times per second, which is something. I measure a high contention, so I'm not even sure it was worth in the end, but I thought it was a good experiment to attempt :)
where I configure the memory-mapped registers of the interrupt controller; "wcb" / "rcb" tags stand for write/read callbacks, which means that specific callbacks (with names matching the register names) will be called for each read/write operation; this is all achieved through reflection. The same applies to mapping the whole register bank, which is done here:
https://github.com/rasky/ndsemu/blob/master/nds9.go#L69
The memory subsystem handling these and more features is in emu/hwio, and I'm actually pretty proud of it. For the memory mapping itself, a radix tree is built which is quite quick to lookup and doesn't require much barcoding.
In fact, the whole "emu" package is a generic framework for emulators in Go, and I plan to reuse it in the future :)
The Octalyzer has separate threads for cpu, sound, memory, networking, graphics and the main opengl loop. We use vertical blanking and sound timing to keep it all in sync.
For interfacing with OS (window, sound, input), I use SDL bindings for Go (go-sdl2). Graphics is 100% being made in RAM pixel by pixel, so SDL is blitting the final image (see the emu/hw package).
Currently the Octalyzer features full-screen Apple IIe emulation with decent compatibility, USB and mouse-controlled joystick support, cloud disk library (when logged-in to Octa-Link), 3D camera support, 3D LOGO, enhanced BASIC interpreters, custom file browser and editor, and remote screen sharing.
A lot of these retro games don't look so authentic on LCD screens because things like blur and shadow masking were actually used by the designers of the original games.
I could care less about games looking like they're "authentic" WRT to curvature or phosphor grid pattern, but things like aspect-ratio correction (non-square pixels), colour switching[0], or cheap transparency tricks through composite[1] are another matter entirely.
Thanks for the link! We don't currently (although there is some rasterisation provided by the OpenGL rendering) but we'll look into some CRT shaders =)
An emulator has been my "bucket-list" ever since I became a software engineer. I still haven't done it...Do you have any good pointers for someone to get started with making an emulator (particularly for someone who works almost exclusively with with server-ey stuff)?
I'm afraid this does not appear to work on my system (Ubuntu 16.04, 64bit). None of the key combos work (Shift-ctrl-` etc.), and dropping an image just crashes it. And I was all geared up for karateka...
In the enterprise world Java did that - even high frequency trading applications have been Java based for quite some time.
Compared to 20years ago, there is significantly less C code nowadays.
These do not look like very credible examples. According to NoVM's GitHub page, it has not been updated in two years. go-tcpip does not actually have a TCP implementation.
If you pointed out similar examples about C in the 80's, I would provide a similar reply, after all any serious programmer targeting the home market would use professional tools like Assembly.
One needs to start somewhere, but apparently to impress HN one needs to hide in some cave and present a done product after some years hiding, as the fashion driven industry has lost most visionaries.
It features both the 2D and the 3D engine (with a full software rasterizer with poly-fillers generated through go generate). It's highly concurrent (each graphic layer is drawn in a different goroutine and then mixed together). The ARM interpreter is also generated via go generate.
I'll add some screenshots at some point.