# lc3-vm: a literate-programming tutorial for writing an LC-3 virtual machine in C

> lc3-vm is a tutorial and working source code for implementing an LC-3 virtual machine, written as a literate program with srcweave. The generated code targets 4 variants (POSIX C, Windows C, POSIX C++ and Windows C++), and the published tutorial at jmeiners.com/lc3-vm/ is the primary product.

**justinmeiners/lc3-vm** — Write your own virtual machine for the LC-3 computer!

- Repository: https://github.com/justinmeiners/lc3-vm
- Website: https://www.jmeiners.com/lc3-vm/
- Stars: 2,097 · Forks: 223
- Language: Makefile
- License: not declared
- Published: 2026-10-11 · Updated: 2026-10-11 · Language: en
- Canonical page: https://hysenlabs.com/projects/justinmeiners-lc3-vm

## lc3-vm teaches virtual machine design through a complete working LC-3 implementation

The repository contains both a written tutorial and working source code for building a virtual machine of the LC-3 computer architecture. The tutorial is published at jmeiners.com/lc3-vm/ and walks through the implementation in prose alongside the code. Anyone who wants a guided introduction to virtual machine design, assembly instruction handling and low-level C programming can follow the tutorial to build their own LC-3 VM from scratch.

The 11 repository topics signal the scope: assembly, c, emulator, lc3, lc3-assembly, literate-programming, low-level, tutorial, tutorials, virtual-machine and vm. This span indicates the project sits at the intersection of educational content and working implementation, aimed at students and hobbyists approaching virtual machine architecture for the first time.

That tutorial is the primary product. It exists to hold the source, host the generated HTML and accept contributions. Neither the README nor the repository structure is designed for someone who wants to import lc3-vm as a library.

## One index.lit file generates 4 C and C++ source variants through literate programming

lc3-vm uses literate programming, a technique where a single source document contains both prose explanations and code fragments. That document is index.lit, at the repository root. srcweave processes it in 2 passes: one tangles it into source code files, and another weaves it into the HTML tutorial with syntax highlighting.

A tangle pass produces 4 files in docs/src/: lc3.c, lc3-win.c, lc3-alt.cpp and lc3-alt-win.cpp. That is a 2-by-2 grid: 2 platform targets (POSIX and Windows) combined with 2 language choices (C and C++). The "-alt" prefix on the C++ files indicates they are alternative implementations, distinct from the C version in design, not just in syntax.

All 4 generated files come from the same index.lit source, which means any change to the implementation is made once in index.lit. The generated .c and .cpp files are outputs, not the place to make edits. Reading them outside the context of the tutorial is possible but misses the inline explanations.

## Building from source requires srcweave, which the README calls non-trivial to set up

Regenerating the source and documentation from index.lit requires srcweave installed locally. Two Makefile targets drive the build:

```makefile
docs/src/lc3.c docs/src/lc3-win.c docs/src/lc3-alt.cpp docs/src/lc3-alt-win.cpp: index.lit
	srcweave --tangle ./docs/src/ $<

docs/index.html: index.lit
	srcweave --weave ./docs/ --styler srcweave-html-styler $<
```

That first target tangles index.lit into the 4 source files. A second target weaves it into the HTML documentation with srcweave-html-styler for code formatting. Both take index.lit as their sole input, so a single edit to that file propagates to all generated outputs on the next build.

For contributors who prefer not to set up srcweave, the README says edits to the .lit file are welcome and the maintainer can handle regeneration. This is the intended contribution path for most people. The 6 top-level entries (.gitignore, Makefile, README.md, assets/, docs/ and index.lit) reflect how the project separates its source (index.lit), its build tooling (Makefile) and its generated artifacts (docs/).

## The 4 generated variants reveal what the literate source covers

The presence of 4 distinct generated files tells something about the depth of the literate source. lc3.c is the primary C implementation for POSIX systems. lc3-win.c adapts it for Windows. lc3-alt.cpp is a separate C++ implementation, not a port of the C code but an alternative approach to the same architecture. lc3-alt-win.cpp is the Windows version of that C++ alternative.

This structure means the tutorial text in index.lit must cover at minimum 2 distinct implementation strategies. A reader following the C path will encounter different constructs from one following the C++ alternative. The README does not describe when to prefer one over the other.

Separate Windows variants for both C and C++ are also notable. These are distinct generated files rather than conditional compilation sections, which means the Windows-specific adaptations required code that could not be written portably across both targets without separate branches in the literate source.

## Different rules apply to the article text and to the generated source code

Two separate sets of terms cover different parts of the project. The article text and all figures fall under CC BY-NC-SA 4.0. Code in lc3.c and the other generated files carries a different short-form permissive set of terms, documented in the README.

Anyone wanting to use, modify or redistribute the code can do so under the terms in the README. For the educational content, CC BY-NC-SA 4.0 applies, which includes a non-commercial restriction and a share-alike requirement.

This split matters most for educators. A course that assigns students to read the tutorial and build their own LC-3 VM runs no risk from either set of terms. A course that wants to reproduce the article text verbatim or use the figures in course materials must comply with the CC BY-NC-SA 4.0 conditions. Both the published tutorial at jmeiners.com/lc3-vm/ and the article content in the repository carry the same CC BY-NC-SA 4.0 terms.

## What the lc3-vm source is not equipped to do

Generated source files are structured to be read alongside the tutorial, not as standalone components. No header files appear among the 6 top-level repository entries, so there is no API for external code to call into the VM. Building produces documentation and standalone source files, not a linkable library.

A reader who follows the tutorial to completion will have a working LC-3 VM. Adapting it for another purpose, such as embedding it in a larger application, extending the instruction set, or adding debugging output, requires departing from the generated files and modifying the literate source directly. That requires understanding the srcweave format as well as the implementation.

For anyone who needs a general-purpose LC-3 emulator rather than a tutorial walkthrough, the project layout is a poor fit. The absence of a test suite, a versioning interface or a documented extension mechanism confirms that the codebase is an educational artifact, not a reusable component.

## Implementing an LC-3 VM without the tutorial narrative

An alternative to following lc3-vm is to implement an LC-3 VM from the LC-3 specification directly, without a narrative guide. The specification defines the instruction set architecture: the opcodes, addressing modes, condition codes and trap routines that any compliant VM must handle. Working from the specification alone is a different exercise from following lc3-vm, because no text explains the decisions made at each step.

lc3-vm's value is not the final code itself but the annotated path to it. The C++ alternative in lc3-alt.cpp shows that the same architecture supports multiple implementation styles. A reader who builds the VM once while reading the tutorial, then tries again from the specification without looking at lc3-vm, will find the two exercises complement each other: one shows one way to structure the code, and the other shows what choices exist when no guide is given.

For someone who only needs the generated source and not the tutorial, cloning the repository and reading the .c and .cpp files directly is possible but leaves the design decisions unexplained.

## Conclusion

lc3-vm is worth reading if you want a guided, annotated walkthrough of virtual machine design using the LC-3 architecture as the target. The tutorial at jmeiners.com/lc3-vm/ is the primary product, and the repository exists to host the source and accept edits through the literate-programming workflow. For a production-ready LC-3 emulator, this codebase is not structured for that purpose: it generates 4 tutorial-oriented source files with no public API, no test suite and no embedding interface. The last push was on 2026-04-02. Before reproducing any part of the article, check the licensing split: the code is MIT-licensed and the article with figures uses CC BY-NC-SA 4.0 terms.

## FAQ

### What is lc3-vm?

lc3-vm is a literate-programming tutorial and working source code for implementing a virtual machine of the LC-3 computer architecture. The tutorial is published at jmeiners.com/lc3-vm/ and the source is generated from a single index.lit file using srcweave.

### Do I need to build lc3-vm locally to follow the tutorial?

The tutorial is published online at jmeiners.com/lc3-vm/ and is readable without any local setup. Building the source locally requires srcweave, which the README warns is non-trivial to configure.

### Can I use the lc3-vm code in commercial projects?

The source code in lc3.c and the other generated files carries a permissive licence documented in the README, which allows commercial use. The article text and figures use CC BY-NC-SA 4.0, which does not permit commercial reproduction of the educational content.

### How do I contribute to lc3-vm?

The README says to edit index.lit and submit the change; the maintainer can regenerate the source and documentation files. Editing the generated .c or .cpp files directly is not the intended contribution path.

### What programming language is lc3-vm written in?

The literate source is in index.lit, which srcweave tangles into 4 files: lc3.c and lc3-win.c in C, and lc3-alt.cpp and lc3-alt-win.cpp in C++. The repository primary language is listed as Makefile because the build tooling drives generation.

## Sources

- [Issues](https://github.com/justinmeiners/lc3-vm/issues)
- [justinmeiners/lc3-vm on GitHub](https://github.com/justinmeiners/lc3-vm)
- [Project website](https://www.jmeiners.com/lc3-vm/)
- [README](https://github.com/justinmeiners/lc3-vm/blob/master/README.md)
- [Releases](https://github.com/justinmeiners/lc3-vm/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/justinmeiners-lc3-vm
