Hello DEV community! 👋
For the past 10 years, I’ve been working on a massive passion project. I wanted to build a cycle-accurate hardware emulator, but I was deeply frustrated by the traditional "monolithic" designs used in most emulators. They are incredibly fast, but they are black boxes.
I wanted to build a software breadboard. A system where I could literally SSH into the running machine and inspect CPU registers on the fly.
So, I built Symphony: A Microkernel OS, a Universal VM, and a Topological Emulator... all written in 100% pure Go (zero CGo!). 🤯
You can play a WebAssembly build of it right now here (running the legendary Mayhem in Monsterland on a virtual C64): https://markel1974.itch.io/symphony
Here is a quick breakdown of how I used Go to build this beast:
The Microkernel OS (Yes, an OS in Go) 🐧
The C64 you see in the browser isn't a standalone loop. It's running as an isolated user-space process inside a Microkernel I built. Using Go's amazing concurrency and interfaces, I built an asynchronous message router. The kernel has a built-in SSH server and a VT100 window manager. This means I can SSH into my running emulator, open the xsh shell, and modify the hardware state at runtime!Ditching the giant switch-case for the Strategy Pattern 🧠
Most emulators use a giant switch-case for the CPU instruction set. I hated that. Instead, I built a Universal VM with an "Interchangeable Instruction Disk" architecture. Every opcode is a Go struct implementing an IOpExecutor interface. The main loop uses direct function pointer dispatch. This means my VM can execute native Go bytecode (compiled by my custom multi-pass Go-to-Bytecode compiler), or it can transform into a cycle-accurate Z80 or MOS6510 CPU just by swapping the sequencer!Topological Hardware (Go Interfaces are magic) 🔌
The hardware components (VIC-II, SID, PLA) don't communicate via software traps. They are completely isolated structs that only know about their ISocket interface. When the VIC-II needs memory, it pulls a simulated DMA line low, triggering the CPU to put its pins into High-Z (high impedance) state. It's literally an electronic breadboard translated into Go interfaces.
Why pure Go?
I wanted memory safety, extreme modularity, and the ability to compile for Desktop (OpenGL), Web (WASM), and Headless servers (for CI/CD testing) with a single command. Go delivered on all fronts.
If you are interested in System Architecture, Emulation, or just want to see how to abuse Go interfaces to simulate hardware pins, check out the source code!
📂 GitHub Repo: https://github.com/markel1974/Symphony
I’d love to know what you think about the architecture! Has anyone else here tried building hardware simulations or VMs in Go? Let's discuss in the comments! 👇
Top comments (0)