Building a Virtual Machine From Scratch Takes Six Hours
A programmer documents building a 16-bit virtual machine in C with custom assembly language, revealing the actual complexity of low-level systems work.
Written by AI. Bob Reynolds
February 11, 2026

Photo: dr Jonas Birch / YouTube
Dr. Jonas Birch spent six hours and twenty-four minutes building a virtual machine from scratch in C, and the footage is instructive precisely because nothing goes smoothly.
This isn't a polished tutorial where everything compiles on the first try. It's a real-time documentation of how someone who's never built a virtual machine before approaches the problem—by making decisions, hitting compiler errors, consulting Google about C enums, and backtracking when the architecture doesn't quite work. The result is more honest than most programming content, and more useful for it.
The Architecture of Simplicity
Birch's virtual machine mimics the constraints of 1980s computing: a 16-bit CPU with 65 kilobytes of memory, six registers (four general-purpose, plus a stack pointer and instruction pointer), and a custom assembly language with instructions like MOVE and NOOP. It's deliberately constrained—no external libraries beyond his own utilities, minimal use of the C standard library.
"This virtual machine will be a 16bit virtual machine," Birch explains early in the video. "So like the 386 computer if you had one of those back in the days."
The choice of 16-bit isn't nostalgia. It's pedagogical. Sixteen bits means 65,536 possible values—small enough to reason about, large enough to be interesting. The entire memory space fits in your head. You can trace what's happening without abstractions hiding the mechanisms.
This matters because understanding virtual machines means understanding computers at their most fundamental level. Every programming language runtime, every emulator, every containerization system—they're all variations on this theme. Build one and you understand them all better.
Data Types First, Everything Else Second
Birch's development methodology is worth noting: he starts by defining data structures, then writes functions that operate on them. It's bottom-up programming, and it shows.
"I'm letting the data types guide the entire project," he says. "And that's a good way to do any project because if you have all the data types, you only need to create the functions that use these data types and you're done."
The approach has advantages. By defining structures for the VM, CPU, registers, memory stack, and instruction set before writing any logic, he's forcing himself to think through the architecture. What does a virtual machine contain? A CPU and memory. What does a CPU contain? Registers. What's a register? An unsigned short int in a 16-bit system.
Each definition cascades into the next. A program is a sequence of instructions. An instruction is an opcode plus arguments. An opcode is an enum. You need a lookup table mapping opcodes to instruction sizes. The table needs its own structure. And so on.
The video shows all of this—the thinking-out-loud process of someone working through architectural decisions in real time. He changes his mind. He restructures things. He hits the limits of what C will allow and finds workarounds. This is software development as it actually happens, not as we pretend it happens in finished tutorials.
Binary Arithmetic and Instruction Encoding
The most technically dense section involves encoding instructions at the bit level. Birch wants to pack both the operation and the target register into a single byte, which means thinking in binary.
For a MOVE instruction that puts the value 5 into the AX register, he needs three bytes total: one byte encoding both the MOVE operation and the AX target, plus two bytes for the value itself. He works through the bit manipulation on screen—using the rightmost four bits for the operation, the next three for the register, leaving four bits unused in the first byte.
"So this whole thing together will be a move to the AX register number five," he explains after walking through the binary representation. "I hope you were able to follow along and if not try rewinding and listen to this once more."
It's the kind of low-level bit manipulation that modern programming usually abstracts away. Most developers never think about how instructions are encoded in memory. They work several layers above this, where compilers and interpreters handle these details. But those layers exist because someone had to solve these problems first.
When The Compiler Fights Back
A substantial portion of the video is debugging. Birch hits errors with typedef ordering, struggles with C enum syntax, and discovers his instruction map initialization doesn't compile the way he expects.
"Unknown type name opcode at line 67 because we define this below," he reads from the compiler output. He reorganizes the typedefs. More errors. "It's always a little bit difficult to put these ones in the correct order."
Later, facing an enum referencing error: "Isn't the whole point that we should be able to reference it with a dot? I will consult Google."
This is programming. Not the cleaned-up version presented in most educational content, but the actual iterative process of writing code, reading compiler errors, making adjustments, and sometimes just trying things to see if they work. When Birch finally gets a successful compilation, he observes: "Okay, we are alive and kicking. Ladies and gentlemen, wasn't this kind of beautiful? I think it's beautiful."
The question is whether six hours of this is more valuable than a one-hour tutorial that skips the debugging. Depends on what you're trying to learn. If you want to understand virtual machines conceptually, the tutorial is probably sufficient. If you want to know what it actually feels like to build one—including the moments where you're not sure if C syntax allows what you're trying to do—then you watch someone work through the problems in real time.
The video is still incomplete at six hours. Birch has defined the data structures, created an instruction map, and written a constructor function for the VM. The machine doesn't actually run anything yet. The assembly language exists only as enum definitions. There's no parser, no execution loop, no I/O.
Which tells you something about the actual complexity involved. Building a functional virtual machine from scratch takes longer than a workday. The finished product would probably run slower than implementations in actual assembly. The custom instruction set won't be compatible with anything.
But that's not the point. Understanding how computers work at this level changes how you think about the abstractions you normally use. Every high-level language feature, every framework convenience, every runtime optimization—they're all solving problems that become visible when you try to build a computer from first principles.
—Bob Reynolds, Senior Technology Correspondent
Watch the Original Video
Coding a Virtual Machine from scratch in C
dr Jonas Birch
6h 24mAbout This Source
dr Jonas Birch
Dr. Jonas Birch has carved a niche in the YouTube technology landscape, captivating over 52,600 subscribers with his adept handling of low-level technical topics. Since launching his channel in September 2025, he has been dedicated to making complex subjects like system architecture and open-source software accessible and engaging, living up to his channel's motto of 'Making low-level popular again.'
Read full source profileMore Like This
When Software 'Works' But You Can't Trust It
A veteran Microsoft engineer explains the difference between software that appears to work and software that actually works—and why that gap matters.
What Actually Happens When You Run printf() in C
Dr. Jonas Birch's tutorial reveals the three-layer journey from C library calls to system calls to CPU instructions—using printf() as the unlikely hero.
Three Hours of Debugging a File Compressor in C
Dr. Jonas Birch spent 3.5 hours live-coding a file compressor in C. What the session reveals about real programming work might surprise you.
Not Every Problem Needs AI. Here's How to Tell.
Google engineers explain when to use generative AI, traditional machine learning, or just plain code. The answer matters more than you'd think.