Skip to content

Instantly share code, notes, and snippets.

@shriram
Created April 4, 2026 04:31
Show Gist options
  • Select an option

  • Save shriram/4c39f5a33db37607e64f760760dbd8d1 to your computer and use it in GitHub Desktop.

Select an option

Save shriram/4c39f5a33db37607e64f760760dbd8d1 to your computer and use it in GitHub Desktop.
Artemis II Tribute Using Apollo Guidance Computer display

Artemis II DSKY tribute — artemis.agc

Credit: the work to generate this code was done by Claude Code using Claude Sonnet 4.6.

A program for the Apollo Guidance Computer (AGC) that displays a tribute to the Artemis II mission on the Apollo DSKY (Display/Keyboard unit). It cycles through three phases, looping forever:

Phase 0   _ _ _ _ 3    "3 2 1"
          _ _ _ _ 2
          _ _ _ _ 1

Phase 1   _ _ 4 1 1    "ALL"
          1 5 _ 9 0    "IS GO"

Phase 2   _ _ 5 3 7    "SET"
          _ 5 4 1 1    "SAIL"

How it works

The AGC communicates with the DSKY by writing 15-bit words to I/O channel 010. Each word encodes a relay address (bits 15–12) and two 5-bit digit patterns. There are 11 relay addresses — three for PROG/VERB/NOUN and eight for the three data registers.

The program uses the T3RUPT timer interrupt to keep the AGC's Night Watchman satisfied, and cycles phases with a simple 16383-iteration countdown loop (~1 second per phase at full clock speed).

Running it

The easiest way is the webAGC browser simulator, which can run arbitrary AGC binaries assembled with yaYUL.

  1. Clone virtualagc/virtualagc and build yaYUL
  2. Assemble: yaYUL artemis.agc → produces artemis.agc.bin
  3. Drop the .bin into your webAGC demo/agc/ folder and add it to the program list in index.html
  4. Serve with npm run serve-dev and open in a browser

Credits

Component What it is Source
Virtual AGC The complete AGC simulation environment, including yaYUL (assembler) and yaAGC (emulator) ibiblio.org/apollo · github.com/virtualagc/virtualagc
yaYUL AGC assembler used to produce the .bin from this source Part of Virtual AGC
webAGC WebAssembly port of yaAGC; runs AGC binaries in the browser Bundled with moonjs
moonjs Browser-based AGC/DSKY simulator providing the UI and DSKY rendering github.com/siravan/moonjs
@wasmer/wasi · @wasmer/wasmfs WASM runtime libraries that webAGC depends on to load the compiled AGC core wasmer.io

The relay-word encoding for channel 010 was derived from piPeripheral.agc in the Virtual AGC source tree.

# artemis.agc
# Artemis II tribute: "3 2 1 ALL IS GO SET SAIL"
#
# Cycles through three phases on the DSKY, looping forever:
#
# Phase 0: "3 2 1"
# R1: _ _ _ _ 3
# R2: _ _ _ _ 2
# R3: _ _ _ _ 1
#
# Phase 1: "411" / "15 90" = "ALL" / "IS GO" (leet: a=4 l=1 l=1 | i=1 s=5 g=9 o=0)
# R1: _ _ 4 1 1
# R2: 1 5 _ 9 0
#
# Phase 2: "537" / "5411" = "SET" / "SAIL" (leet: s=5 e=3 t=7 | s=5 a=4 i=1 l=1)
# R1: _ _ 5 3 7
# R2: _ 5 4 1 1
#
# DSKY digit relay patterns (5-bit codes, decimal):
# blank=0 0=21 1=3 2=25 3=27 4=15 5=30 6=28 7=19 8=29 9=31
#
# Channel 010 word: relay_addr*2048 + left_digit*32 + right_digit
# Relay 11=PROG 10=VERB 9=NOUN
# Relay 8=R1d1 7=R1d2,R1d3 6=R1d4,R1d5
# Relay 5=R2d1,R2d2 4=R2d3,R2d4 3=R2d5,R3d1
# Relay 2=R3d2,R3d3 1=R3d4,R3d5
# ---------------------------------------------------------------
# Named CPU registers
# ---------------------------------------------------------------
A EQUALS 0
L EQUALS 1
Q EQUALS 2
EBANK EQUALS 3
FBANK EQUALS 4
Z EQUALS 5
BBANK EQUALS 6
ARUPT EQUALS 10
LRUPT EQUALS 11
QRUPT EQUALS 12
SAMPTIME EQUALS 13
ZRUPT EQUALS 15
BANKRUPT EQUALS 16
BRUPT EQUALS 17
CYR EQUALS 20
SR EQUALS 21
CYL EQUALS 22
EDOP EQUALS 23
TIME2 EQUALS 24
TIME1 EQUALS 25
TIME3 EQUALS 26
TIME4 EQUALS 27
TIME5 EQUALS 30
TIME6 EQUALS 31
# ---------------------------------------------------------------
# Erasable memory
# ---------------------------------------------------------------
SETLOC 67
NEWJOB ERASE # Night Watchman check address (must be at octal 067)
TIMER ERASE # Phase display countdown timer
# ---------------------------------------------------------------
# Interrupt vector table — MUST start at address 04000
# ---------------------------------------------------------------
SETLOC 4000
# Power-on / restart vector
INHINT # Disable interrupts during init
CA O37774
TS TIME3 # Prime the T3 timer
TCF STARTUP
# T6RUPT — not used
RESUME
NOOP
NOOP
NOOP
# T5RUPT — not used
RESUME
NOOP
NOOP
NOOP
# T3RUPT — must service the recurring timer
DXCH ARUPT
EXTEND
QXCH QRUPT
TCF T3RUPT
# T4RUPT — not used
RESUME
NOOP
NOOP
NOOP
# KEYRUPT1 — not used
RESUME
NOOP
NOOP
NOOP
# KEYRUPT2 — not used
RESUME
NOOP
NOOP
NOOP
# UPRUPT — not used
RESUME
NOOP
NOOP
NOOP
# DOWNRUPT — not used
RESUME
NOOP
NOOP
NOOP
# RADAR RUPT — not used
RESUME
NOOP
NOOP
NOOP
# RUPT10 — not used
RESUME
NOOP
NOOP
NOOP
# ---------------------------------------------------------------
# T3RUPT handler: reload TIME3 and return
# ---------------------------------------------------------------
T3RUPT CAF O37774
TS TIME3
DXCH ARUPT
EXTEND
QXCH QRUPT
RESUME
# ---------------------------------------------------------------
# STARTUP: blank PROG, VERB, NOUN; fall into Phase 0
# ---------------------------------------------------------------
STARTUP RELINT
CA OPCODEP
EXTEND
WRITE 10
CA OPCODEV
EXTEND
WRITE 10
CA OPCODEN
EXTEND
WRITE 10
# ---------------------------------------------------------------
# Phase 0: "3 2 1"
# ---------------------------------------------------------------
PHASE0 CA P0_R8 # relay 8: R1d1 = blank
EXTEND
WRITE 10
CA P0_R7 # relay 7: R1d2,R1d3 = blank,blank
EXTEND
WRITE 10
CA P0_R6 # relay 6: R1d4=blank, R1d5=3
EXTEND
WRITE 10
CA P0_R5 # relay 5: R2d1,R2d2 = blank,blank
EXTEND
WRITE 10
CA P0_R4 # relay 4: R2d3,R2d4 = blank,blank
EXTEND
WRITE 10
CA P0_R3 # relay 3: R2d5=2, R3d1=blank
EXTEND
WRITE 10
CA P0_R2 # relay 2: R3d2,R3d3 = blank,blank
EXTEND
WRITE 10
CA P0_R1 # relay 1: R3d4=blank, R3d5=1
EXTEND
WRITE 10
CA TIMERVAL
TS TIMER
LOOP0 CS NEWJOB # feed Night Watchman
CCS TIMER
TCF DECR0 # TIMER > 0: decrement and loop
TCF PHASE1 # TIMER = +0: advance
TCF PHASE1 # TIMER < 0: shouldn't happen
TCF PHASE1 # TIMER = -0: shouldn't happen
DECR0 TS TIMER # store TIMER-1 (A set by CCS above)
TCF LOOP0
# ---------------------------------------------------------------
# Phase 1: "411 15 90" = ALL IS GO
# ---------------------------------------------------------------
PHASE1 CA P1_R8 # relay 8: R1d1=4
EXTEND
WRITE 10
CA P1_R7 # relay 7: R1d2=1, R1d3=1
EXTEND
WRITE 10
CA P1_R6 # relay 6: R1d4=1, R1d5=5
EXTEND
WRITE 10
CA P1_R5 # relay 5: R2d1,R2d2 = blank,blank
EXTEND
WRITE 10
CA P1_R4 # relay 4: R2d3=blank, R2d4=9
EXTEND
WRITE 10
CA P1_R3 # relay 3: R2d5=0, R3d1=blank
EXTEND
WRITE 10
CA P1_R2 # relay 2: R3d2,R3d3 = blank,blank
EXTEND
WRITE 10
CA P1_R1 # relay 1: R3d4,R3d5 = blank,blank
EXTEND
WRITE 10
CA TIMERVAL
TS TIMER
LOOP1 CS NEWJOB
CCS TIMER
TCF DECR1
TCF PHASE2
TCF PHASE2
TCF PHASE2
DECR1 TS TIMER
TCF LOOP1
# ---------------------------------------------------------------
# Phase 2: "537 5411" = SET SAIL
# ---------------------------------------------------------------
PHASE2 CA P2_R8 # relay 8: R1d1=5
EXTEND
WRITE 10
CA P2_R7 # relay 7: R1d2=3, R1d3=7
EXTEND
WRITE 10
CA P2_R6 # relay 6: R1d4=5, R1d5=4
EXTEND
WRITE 10
CA P2_R5 # relay 5: R2d1,R2d2 = blank,blank
EXTEND
WRITE 10
CA P2_R4 # relay 4: R2d3=blank, R2d4=1
EXTEND
WRITE 10
CA P2_R3 # relay 3: R2d5=1, R3d1=blank
EXTEND
WRITE 10
CA P2_R2 # relay 2: R3d2,R3d3 = blank,blank
EXTEND
WRITE 10
CA P2_R1 # relay 1: R3d4,R3d5 = blank,blank
EXTEND
WRITE 10
CA TIMERVAL
TS TIMER
LOOP2 CS NEWJOB
CCS TIMER
TCF DECR2
TCF PHASE0 # wrap back to beginning
TCF PHASE0
TCF PHASE0
DECR2 TS TIMER
TCF LOOP2
# ---------------------------------------------------------------
# Constants
# ---------------------------------------------------------------
O37774 OCT 37774 # TIME3 reload value for T3RUPT
TIMERVAL DEC 16383 # phase display duration (~1 sec at divisor=1)
# Channel 010 relay-word bases (relay N * 2048)
# Relays 9-11 are negative in 15-bit 1's complement (N*2048 > 16383)
OPCODEP DEC 11 B11 # PROG relay 11
OPCODEV DEC 10 B11 # VERB relay 10
OPCODEN DEC 9 B11 # NOUN relay 9
# --------------- Phase 0 constants: "3 2 1" ---------------
# word = relay_addr*2048 + left_digit*32 + right_digit
# Relays 8+ use OCT notation (value > 16383, so negative in 1's complement)
P0_R8 OCT 040000 # relay 8, R1d1=blank: 8*2048+0 = 16384
P0_R7 DEC 14336 # relay 7, R1d2,d3=blank,blank: 7*2048 = 14336
P0_R6 DEC 12315 # relay 6, R1d4=blank,R1d5=3: 6*2048+27 = 12315
P0_R5 DEC 10240 # relay 5, R2d1,d2=blank,blank: 5*2048 = 10240
P0_R4 DEC 8192 # relay 4, R2d3,d4=blank,blank: 4*2048 = 8192
P0_R3 DEC 6944 # relay 3, R2d5=2,R3d1=blank: 3*2048+25*32 = 6944
P0_R2 DEC 4096 # relay 2, R3d2,d3=blank,blank: 2*2048 = 4096
P0_R1 DEC 2051 # relay 1, R3d4=blank,R3d5=1: 1*2048+3 = 2051
# --------------- Phase 1 constants: "411" / "15 90" = ALL / IS GO ---------------
# R1: _ _ 4 1 1 R2: 1 5 _ 9 0
P1_R8 OCT 040000 # relay 8, R1d1=blank: 8*2048 = 16384
P1_R7 DEC 14351 # relay 7, R1d2=blank,R1d3=4: 7*2048+15 = 14351
P1_R6 DEC 12387 # relay 6, R1d4=1,R1d5=1: 6*2048+3*32+3 = 12387
P1_R5 DEC 10366 # relay 5, R2d1=1,R2d2=5: 5*2048+3*32+30= 10366
P1_R4 DEC 8223 # relay 4, R2d3=blank,R2d4=9: 4*2048+31 = 8223
P1_R3 DEC 6816 # relay 3, R2d5=0,R3d1=blank: 3*2048+21*32 = 6816
P1_R2 DEC 4096 # relay 2, R3d2,d3=blank,blank: 2*2048 = 4096
P1_R1 DEC 2048 # relay 1, R3d4,d5=blank,blank: 1*2048 = 2048
# --------------- Phase 2 constants: "537" / "5411" = SET / SAIL ---------------
# R1: _ _ 5 3 7 R2: _ 5 4 1 1
P2_R8 OCT 040000 # relay 8, R1d1=blank: 8*2048 = 16384
P2_R7 DEC 14366 # relay 7, R1d2=blank,R1d3=5: 7*2048+30 = 14366
P2_R6 DEC 13171 # relay 6, R1d4=3,R1d5=7: 6*2048+27*32+19=13171
P2_R5 DEC 10270 # relay 5, R2d1=blank,R2d2=5: 5*2048+30 = 10270
P2_R4 DEC 8675 # relay 4, R2d3=4,R2d4=1: 4*2048+15*32+3= 8675
P2_R3 DEC 6240 # relay 3, R2d5=1,R3d1=blank: 3*2048+3*32 = 6240
P2_R2 DEC 4096 # relay 2, R3d2,d3=blank,blank: 2*2048 = 4096
P2_R1 DEC 2048 # relay 1, R3d4,d5=blank,blank: 1*2048 = 2048
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment