This is a browser-based control panel for a real Apollo Guidance Computer
(AGC) emulator. It runs an actual excerpt of the Apollo 11 flight software —
the sine/cosine routine (SPCOS/SPSIN) from LUMINARY099, the real Lunar
Module guidance software — and lets you step through it, instruction by
instruction, watching the computer's internal state change in real time.
Open agc_visual_emulator.html in any browser. No installation, no server,
no internet connection required after the page loads (it does load two web
fonts on first open; everything else is self-contained).
- Background: what the AGC actually was
- The registers
- Reading the numbers: octal and one's-complement fractions
- The source code panel
- Running the program
- Testing a specific angle (the keypad)
- Checking the answer
- Instruction glossary
- Directive glossary (the non-instruction lines)
- A worked example: the first 8 steps, explained
- Troubleshooting / FAQ
- What this emulator is (and isn't)
The Apollo Guidance Computer flew both the Command Module and the Lunar Module. It's nothing like a modern chip — no gigabytes, no floating point, no operating system in the modern sense. It had a small fixed set of simple instructions (things like "add these two numbers," "copy this value here," "jump to a different part of the program") and a small number of memory slots it used to hold whatever it was currently working on. Astronauts interacted with it through a keypad-and-display unit called the DSKY, entering two-digit "Verb" and "Noun" codes (e.g. "display velocity") rather than typing anything resembling modern commands.
Big mission-critical software — like the program that guided the lunar
landing — was built out of hundreds of small, reused pieces exactly like
the routine loaded in this emulator. Sine and cosine were needed constantly
throughout the guidance software (for converting between reference frames,
computing engine gimbal angles, orbital predictions, and more), so a
compact, fast routine like SPCOS/SPSIN would have been called
extremely often — this genuinely is one real gear from the real machine.
The dark panel on the left is styled after the real DSKY, but every number on it is live emulator state, not decoration.
| Register | What it means | Shown on panel? |
|---|---|---|
| Z — Program Counter | Which instruction is about to run next. Advances automatically, like a finger moving down a line of text. | Yes |
| A — Accumulator | The main "scratchpad" register. Nearly every instruction reads from or writes to A — this is where arithmetic actually happens. | Yes |
| L — Lower Order | A second scratchpad, used alongside A for instructions needing extra precision (double-precision multiply/double steps). | Yes |
| Q — Return Address | Remembers "where to come back to" after the program jumps into a subroutine — the AGC's mechanism for calling and returning from functions. | Yes |
| EB, FB | Memory bank-select registers (which block of memory is currently "switched in"). Not used meaningfully by this particular routine. | No — internal only |
| BB | A bank/register used by certain real instructions this demo doesn't exercise. | No — internal only |
- EXTEND — a one-shot flag. The AGC didn't have room to encode every
instruction directly, so a handful (multiply, divide, and a few others)
only take effect if the immediately preceding instruction was
EXTEND. It automatically resets after being consumed once. - OVERFLOW — set when an arithmetic result doesn't fit in the available
space. The real flight code deliberately uses this as a signal — see the
TSentry in the glossary below for a concrete example of that trick. - CYCLES — a running total of instructions executed so far.
Two unfamiliar things will jump out immediately, and both are intentional, faithful choices rather than quirks of this particular emulator:
Addresses are shown in octal (base 8). The real AGC's hardware and all of its original documentation used octal, so the emulator does too, to stay faithful to how the actual source code and manuals describe addresses. You don't need to do octal arithmetic yourself — just treat each address as a label, the same way you'd treat a line number.
Values in A and L are fractions, not whole numbers. The AGC didn't have a general-purpose "integer" or "float" type — everything was a 15-bit number, almost always interpreted as a fraction between -1 and +1. That's why an angle like -30° shows up internally as roughly -0.16669 (a fraction of a half-circle) rather than "-30." The small number in parentheses next to A and L is this fraction, decoded for you automatically — you never have to convert it by hand.
There's a second, subtler detail worth knowing: the AGC used one's
complement arithmetic instead of the two's complement your phone or
laptop uses internally. The practical effect you might notice: there are
two ways to represent zero (+0 and -0), and the real flight code
occasionally makes deliberate use of that fact (see CCS in the glossary).
You don't need to understand the mechanics of one's complement to use the
emulator — just don't be surprised if you spot a -0 somewhere.
The text box on the right shows the actual AGC assembly code, copied from the real Apollo 11 repository, plus a small test program of our own added at the bottom (clearly marked in a comment) that calls the real routine and stores its result. You can edit this text directly — it isn't locked.
- Assemble & Load — takes whatever's in the text box and prepares it to run (like compiling). You'll see a green "✓ assembled OK" message, or a red error message describing what's wrong if something doesn't parse.
- start at: — a dropdown listing every labeled location in the program. Lets you begin execution somewhere other than the default entry point.
- Reset to demo source — restores the original text if you've edited it and want to return to a known-good starting point.
- Step — executes exactly one instruction, then stops. This is the best way to actually learn what's happening: watch which register changes after each click, and follow along with the corresponding line in the source panel.
- Run — executes continuously and automatically, at a speed set by the slider (instructions per tick). Pause stops it mid-run.
- Reset CPU — reloads the currently assembled program from the beginning, clearing all registers to zero, without needing to re-assemble.
The scrolling log on the right records every instruction as it runs: address, instruction name, what it operated on, and the resulting value of A. The most recent line is highlighted; scroll up to review earlier steps.
A small table showing the live value of the key variables the routine uses:
TEMK (a scratch variable), SQ (the squared angle), ARGVAL (the input
angle), RESSIN/RESCOS (the final answers), and the polynomial's
constants (C5/2, C3/2, C1/2, LIMITS). Useful for watching the math
develop without tracking A and L by hand the whole way through.
The keypad below the registers lets you try the routine with a different input angle without editing the source text yourself:
- Type a number using the digit keys (e.g.
3,0for 30). - Press +/− to make it negative (recommended — see below).
- Press ENTR. This patches the angle into the source, re-assembles, runs the whole program automatically, and shows you the result.
Other keypad buttons:
| Key | Action |
|---|---|
| CLR | Clears whatever you've typed into the entry field so far. |
| PRO / STEP | Same as the Step button — a nod to the real DSKY's "PRO" (proceed) key. |
| RSET | Full reset: restores the original demo source and reloads it. |
| KEY REL | Toggles Run/Pause. |
Try -30 first. If you enter a positive angle instead, you'll notice
the sine result is still correct, but the cosine result comes back wrong
(0, instead of the expected value). This is a real, documented limitation
of this emulator, not a malfunction: the actual flight code uses a subtle
address-arithmetic trick (an INDEX-based "quadrant folding" step, used
whenever the routine needs to handle certain wider angle ranges) that this
simplified emulator doesn't reproduce bit-for-bit. Negative angles between
0° and -90° avoid that code path entirely and will always check out
correctly. This is flagged directly on the panel so it's visible rather
than hidden.
The Verify against libm panel at the bottom compares the emulator's computed sine and cosine against your browser's own built-in math functions — the "known correct" reference. A green PASS badge means they matched closely (within 0.01); the diff value shows exactly how close. This is the most direct way to confirm: real 1969 flight code, running today, actually computes the right answer.
These are the ones you'll actually see as you step through the default program — worth understanding in detail.
| Mnemonic | Name | What it does |
|---|---|---|
| CA | Clear and Add | Loads a value from memory into A, replacing whatever was there. |
| CS | Clear and Subtract | Loads the negative of a memory value into A. |
| TS | Transfer to Storage | Copies A into a memory location. Also checks the OVERFLOW flag: if the previous math operation overflowed, TS skips the next instruction — the real flight code uses this deliberately, to branch into "handle this special case" code only when needed, without a separate if instruction. |
| TC | Transfer Control | Jumps to another address, and — critically — saves "the address right after this one" into Q first. This is how the AGC calls a subroutine. There's a special case: TC Q (jumping specifically to address 2, which is where Q itself lives) doesn't jump to address 2 — real AGC hardware treats this as "jump to whatever address Q is currently holding," which is exactly how a subroutine returns to its caller. |
| TCF | Transfer Control, Fixed | An unconditional jump that does not save a return address. Used for plain "go to this other part of the code" moves. |
| XCH | Exchange | Swaps the values in A and a memory location. |
| AD | Add | Adds a memory value into A. |
| COM | Complement | Flips the sign of A (turns a positive number negative, or vice versa). |
| DOUBLE | Double | Shorthand for "add A to itself" — doubles the accumulator. |
| DDOUBL | Double-precision Double | Like DOUBLE, but operates across both A and L together for extra precision. |
| EXTEND | Extend prefix | Arms the next instruction to use the AGC's secondary instruction set (needed before MP, for example). Affects nothing by itself. |
| MP | Multiply | Multiplies A by a memory value (only valid immediately after EXTEND). This is the core operation used repeatedly to evaluate the sine/cosine polynomial. |
| INDEX | Index | Reads a value from memory and uses it to modify the address used by the very next instruction. This is the AGC's only form of indirect addressing, and it's the mechanism behind the "quadrant folding" trick mentioned above. |
You won't see these in the default demo, but they're fully implemented, so if you write or paste in additional real AGC code, they'll work correctly:
| Mnemonic | What it does |
|---|---|
| CCS | Compare and Skip — a four-way branch based on whether a memory value is positive, +0, negative, or -0. This was the AGC's primary way of implementing if logic. |
| ADS | Add to Storage — adds A into a memory location and leaves the result in both places. |
| MASK / MSK | Bitwise AND between A and a memory value. |
| DXCH | Double-precision exchange — swaps A/L with a pair of adjacent memory locations at once. |
| DCA | Double Clear and Add — loads a two-word (double-precision) value into A/L. |
| DCS | Double Clear and Subtract — like DCA, but negated. |
| INCR | Increments a memory location by 1. |
| AUG | Augment — increases a value's magnitude by 1 (moves it further from zero, preserving sign). |
| DIM | Diminish — decreases a value's magnitude by 1 (moves it toward zero), stopping at zero. |
| NOOP | Does nothing for one instruction cycle — used for timing or as a placeholder. |
| RELINT / INHINT | Enable / disable interrupts (this emulator tracks the flag but doesn't implement a real interrupt system). |
| DV | Divide — divides A by a memory value (after EXTEND). |
| SU | Subtract — subtracts a memory value from A (after EXTEND). |
| MSU | Modular Subtract — a variant of subtract used for angle-difference calculations. |
| BZF | Branch if Zero — jumps if A is zero (either +0 or -0). |
| BZMF | Branch if Minus or Zero — jumps if A is negative or -0. |
| EDRUPT / RESUME | Interrupt-related instructions; implemented as no-ops here since there's no real interrupt system in this emulator. |
Not every line in the source is an instruction — some are directives, instructions to the assembler itself rather than to the CPU:
| Directive | What it does |
|---|---|
| OCT | Defines a memory word using an octal literal (e.g. OCT 20000). |
| DEC | Defines a memory word using an ordinary decimal fraction (e.g. DEC .7853134), automatically converted into the AGC's internal number format. |
| ERASE | Reserves a blank, writable memory location and gives it a name — this is how the program declares a "variable." |
= (also written EQUALS) |
Defines a named constant equal to another symbol or number, without using up a memory word (e.g. HALF = BIT14). |
| BLOCK, BANK, SETLOC, COUNT, and similar | Real yaYUL directives concerned with which physical memory bank code should be placed in. The emulator recognizes and safely ignores these, since it uses one simplified flat memory space rather than the real multi-bank hardware layout. |
If you click Assemble & Load followed by Step eight times on the default -30° program, here's exactly what you'll see (values shown are the state after each click):
| # | Instruction | A becomes | What just happened |
|---|---|---|---|
| 1 | CA ARGVAL |
-0.16669 | Loads the test angle into A. |
| 2 | TC SPSIN |
-0.16669 | Jumps into the sine routine; Q now remembers where to come back to. |
| 3 | TS TEMK |
-0.16669 | Parks the angle into a scratch variable, TEMK. |
| 4 | TCF SPT |
-0.16669 | Skips past a correction step that isn't needed this time. |
| 5 | DOUBLE |
-0.33337 | First real math: doubles the angle. |
| 6 | TS TEMK |
-0.33337 | Stores the doubled value back into TEMK. |
| 7 | TCF POLLEY |
-0.33337 | Jumps into the actual polynomial formula. |
| 8 | EXTEND |
-0.33337 | Arms the next instruction (a multiply) — no value change. |
One click later, MP TEMK squares the angle (-0.33337 × -0.33337 ≈
+0.11115) — the first step of the polynomial approximation itself. From
there, the pattern repeats a few more times (multiply by a constant, add a
constant) using a technique called Horner's method, before a final
TC Q sends execution back to where it started, with the finished answer
sitting in A.
"✕ error(s)" appears after Assemble & Load. The status line lists what went wrong — usually an undefined symbol (a typo in a label name) or a missing operand. Fix the line it points to and click Assemble & Load again.
Execution stopped and "Halted / looping" appeared.
This isn't a crash. It means either (a) the program reached its intentional
infinite loop at the very end (labeled DONE in the demo — real AGC idle
code spins like this too, waiting for the next task), or (b) execution
landed on a memory address that isn't valid code. Check where Z stopped
against the source panel.
I entered a positive angle and cosine came back as 0. Expected — see the note in section 6 above. This is a documented limitation, not a bug.
I edited the source and now nothing works. Click Reset to demo source to get back to a known-good starting point, then make smaller changes and re-assemble after each one.
What do the tiny lights above the registers mean?
They're styled after the real DSKY's status lamps (PROG, STBY, OPR ERR, etc.). A few are wired to real state — OPR ERR lights up on an
assembly error, STBY lights when halted, PROG lights while running —
the rest are cosmetic, matching the real panel's layout.
This runs real, authentic instruction semantics for the AGC's Block II architecture — the same one's-complement arithmetic, the same instruction behaviors, and an actual excerpt of the real flight software. It is not a full recreation of the physical AGC hardware or the complete Apollo guidance software: there's no DSKY Verb/Noun program interface, no live sensor input, no interrupt scheduler, and only one small routine is loaded rather than the full flight rope (which was tens of thousands of lines). Think of it as a magnifying glass on one real, correctly-behaving gear from the actual machine — not a flyable replica of the whole computer.
For a full, bit-exact recreation of the real hardware capable of running the complete original flight software (including a working simulated DSKY), see the Virtual AGC project.