copyjumpvm

History

Origin & motivation: see compression_intelligence.md (the Hutter-Prize thesis this build log descends from). Research directions: see research_roadmap.md. Reasoned evolution: see design_evolution.md.

2026-10-17 — control track: software call stack + C-like compiler (cc.py)

Implemented the call stack (software stack of return addresses, returned via j @reg) and a C-borrowed function language (int f(int a, int b) { … }), compiled by cc.py to copyjump with synthesized arithmetic (adder/subtractor/ comparators from gates — no ALU). See callstack_language.md.

Verified: sum(3,5)→8; countdown(5)→[5,4,3,2,1] (recursion); sum(255,1) →0 (8-bit overflow). Limitation (v1): non-tail recursion needs callee-saved registers. See design_evolution.md §10.


2026-10-17 — data-structure tower: software stack (push/pop) via peek/poke

Built the first data structure on the substrate: a stack — a 13-bit stack pointer + poke (push) / peek (pop), with ripple increment/decrement for the pointer. stack_demo_gen.py → program_stack_demo.prg.txt (push 0,1,1, pop → [1, 1, 0]), verified. See design_evolution.md §9.


2026-10-17 — md5_gen.py: share register rotation + rotate; the round-loop finding

Shared the remaining fixed-address bodies (register rotation A=D,D=C,C=B,B=BNEW ×64 → one body; left-rotate → 16 bodies by shift amount). program_md5.prg.txt: 36,865 → 28,272 instructions (~9× smaller than the original 260,996).

Also recorded a negative result: the “collapse the 64 rounds into a loop” step is a non-optimization here — in a no-ALU machine, immediate constants beat data tables (a loop needs table init + peek + address arithmetic, which costs more than the immediates it replaces). See design_evolution.md §8.


2026-10-17 — peek/poke: indirect addressing as an addressing mode

Extended CopyJumpMachine.py with indirect addressing: an operand prefixed with @ is dereferenced (the 13-bit value at that address is the actual address) — m dst @src (peek), m @dst src (poke), j @reg (computed goto). Added as an addressing mode, not a new opcode, so the machine stays OISC / URISC. Verified by program_indirect_demo.prg.txt (peek + poke) and a computed-goto check; MD5 and the outliner demos still pass (no regression).

This makes pointers expressible — the primitive that unlocks arrays, heap, stacks, call-stacks (recursion), and linked structures, all built in software.


2026-10-17 — md5_gen.py: also share the round function (F/G/H/I)

Continuing the reuse-aware codegen: the F/G/H/I round functions (fixed addresses B, C, D → F) are now shared as 4 subroutines, called 16× each — like add32. program_md5.prg.txt: 65,637 → 36,865 instructions (47,326 lines), still verified against hashlib (all RFC 1321 vectors).

Cumulative: 260,996 → 65,637 (add32) → 36,865 (add32 + round function), ~7× smaller than the original inlined program, entirely from source-level reuse.


2026-10-17 — md5_gen.py: reuse-aware codegen (shared add32 subroutines)

The MD5 generator now emits shared add32 subroutines instead of inlining the ~769-instruction body 260 times. Each distinct (dst, a, b) signature is written once (fixed addresses) and called via a return register + dispatch tree — source-level reuse, no post-hoc detection.

This is the “generator should be aware of the optimizations from the start” idea — the generator knows its patterns by name, so it never emits the duplicated code in the first place (vs. outliner.js, which rediscovers duplication post-hoc in code it didn’t generate).


2026-10-17 — outliner.js: inlining → subgraph reuse (graph rewrite)

A Node rewriter (vm_programs/outliner.js) that turns inlined copy+jump code into shared subgraphs — the inverse of inlining, implementing strategy 2 from docs/reuse_graphs_paths.md (return register + dispatch tree, no call stack).

How it works

Verified (semantics-preserving)

vm_programs/verify_outliner.py runs original vs rewritten under CopyJumpMachine.py and asserts identical output bits.

Files

Notes / limits


2026-08-30 — MD5 in copyjump (single-block, run via the Python runner)

Full MD5 computed entirely from copy+jump primitives, executed by the “pythonic runner” vm_programs/CopyJumpMachine.py.

What was built

File Role
vm_programs/md5_gen.py generator: emits program_md5.prg.txt
vm_programs/program_md5.prg.txt generated MD5 program (65,637 instructions)
vm_programs/md5_reference.py expected digests via hashlib
vm_programs/md5_check.py runs the program in the VM and diffs vs hashlib
vm_programs/md5.md design notes (memory layout, primitives, round structure)

How it works

Every MD5 operation is lowered to bit-level copy+jump code:

The standard MD5 structure is followed: per round compute F/G/H/I(B,C,D), then F += A + K[i] + M[g], B += leftrotate(F, s[i]), rotate registers A=D, D=C, C=B, and finally add the initial constants back (a0 += A, b0 += B, c0 += C, d0 += D). Bits are LSB-first throughout.

Verification

python3 vm_programs/md5_check.py → PASS against hashlib:

Also verified through the CLI entry point (python3 vm_programs/CopyJumpMachine.py vm_programs/program_md5.prg.txt), which emits the 16 digest bytes LSB-first.

Usage / play

python3 vm_programs/md5_reference.py          # expected digests
python3 vm_programs/md5_gen.py                # (re)generate the program
python3 vm_programs/md5_check.py              # run in VM + diff vs hashlib
python3 vm_programs/CopyJumpMachine.py vm_programs/program_md5.prg.txt

Change the embedded message by editing MESSAGE at the top of md5_gen.py, then re-running the generator.

Scope / notes


2026-08-27 — xorshift32: 5-stage build (XOR gate → PRNG)

All five stages are complete and verified.

What was built (all textual, run via CopyJumpMachine.py — no export)

Stage File Result
1. XOR gate vm_programs/program_xor_gate.prg.txt ✅ 4/4 truth-table cases pass
2. Reference xorshift32 vm_programs/xorshift32_reference.py ✅ outputs match expected
3. Countdown loop-count vm_programs/program_countdown.prg.txt ✅ counts 10 → 1, terminates
4. One number from seed vm_programs/program_xorshift32_step.prg.txt ✅ 0x87985AA5
5. N numbers in loop vm_programs/program_xorshift32_loop.prg.txt ✅ all 10 match reference

Plus the generator: vm_programs/xorshift32_gen.py (emits stages 4 & 5).

Verification highlights

How to use / play with it

# XOR gate (type/pass two bits)
printf '1\n0\n' | python3 vm_programs/CopyJumpMachine.py vm_programs/program_xor_gate.prg.txt

# Reference PRNG (play with seed/n)
python3 vm_programs/xorshift32_reference.py 0x12345678 10
python3 vm_programs/xorshift32_reference.py 1 5

# Countdown
python3 vm_programs/CopyJumpMachine.py vm_programs/program_countdown.prg.txt

# One number / N numbers
python3 vm_programs/CopyJumpMachine.py vm_programs/program_xorshift32_step.prg.txt
python3 vm_programs/CopyJumpMachine.py vm_programs/program_xorshift32_loop.prg.txt

Changing the embedded constants (as requested, documented in comments)

Design notes

Everything is non-interactive (no in reads) so it’s deterministic and directly diffable against the Python reference.

Files created

Possible next steps