6.8 KiB
PR-05 — Core arithmetic + comparisons in VM (int/bounded/bool)
Why: The minimal executable PBS needs arithmetic that doesn’t corrupt stack.
Scope
-
Implement v0 numeric opcodes (slot-safe):
IADD, ISUB, IMUL, IDIV, IMODICMP_EQ, ICMP_NE, ICMP_LT, ICMP_LE, ICMP_GT, ICMP_GEBADD, BSUB, ...(or unify with tagged values)
-
Define conversion opcodes if lowering expects them:
BOUND_TO_INT,INT_TO_BOUND_CHECKED(trap OOB)
Deliverables
-
Deterministic traps:
TRAP_DIV_ZEROTRAP_OOB(bounded checks)
Tests
- simple arithmetic chain
- div by zero traps
- bounded conversions trap on overflow
Acceptance
- Arithmetic and comparisons are closed and verified.
PR-06 — Control flow opcodes: jumps, conditional branches, structured “if”
Why: if must be predictable and verifier-safe.
Scope
-
Implement opcodes:
JMP <i32 rel>JMP_IF_TRUE <i32 rel>JMP_IF_FALSE <i32 rel>
-
Verifier rules:
- targets must be valid instruction boundaries
- stack height at join points must match
Tests
- nested if
- if with empty branches
- branch join mismatch rejected
Acceptance
- Control flow is safe; no implicit stack juggling.
PR-07 — Calling convention v0: CALL / RET / multi-slot returns
Why: Without a correct call model, PBS isn’t executable.
Scope
-
Introduce
CALL <u16 func_id>- caller pushes args (slots)
- callee frame allocates locals
-
Introduce
RET- callee must leave exactly
return_slotson operand stack atRET - VM pops frame and transfers return slots to caller
- callee must leave exactly
-
Define return mechanics for
void(return_slots=0)
Deliverables
-
FunctionTableindexing and bounds checks -
Deterministic traps:
TRAP_INVALID_FUNCTRAP_BAD_RET_SLOTS
Tests
fn add(a:int,b:int):int { return a+b; }- multi-slot return (e.g.,
Padflattened) - void call
Acceptance
- Calls are stable and stack-clean.
PR-08 — Host syscalls v0: stable ABI, multi-slot args/returns
Why: PBS relies on deterministic syscalls; ABI must be frozen and enforced.
Scope
-
Unify syscall invocation opcode:
SYSCALL <u16 id> <u8 arg_slots> <u8 ret_slots>
-
Runtime validates:
- pops
arg_slots - pushes
ret_slots
- pops
-
Implement/confirm:
GfxClear565 (0x1010)InputPadSnapshot (0x2010)InputTouchSnapshot (0x2011)
Deliverables
-
A
SyscallRegistrymapping id -> handler + signature -
Deterministic traps:
TRAP_INVALID_SYSCALLTRAP_SYSCALL_SIG_MISMATCH
Tests
- syscall isolated tests
- wrong signature traps
Acceptance
- Syscalls are “industrial”: typed by signature, deterministic, no host surprises.
PR-09 — Debug info v0: spans, symbols, and traceable traps
Why: Industrial debugging requires actionable failures.
Scope
-
Add optional debug section:
- per-instruction span table (
pc -> (file_id, start, end)) - function names
- per-instruction span table (
-
Enhance trap payload with debug span (if present)
Tests
- trap includes span when debug present
- trap still works without debug
Acceptance
- You can pinpoint “where” a trap happened reliably.
PR-10 — Program image + linker: imports/exports resolved before VM run
Why: Imports are compile-time, but we need an industrial linking model for multi-module PBS.
Scope
-
Define in bytecode:
exports: symbol -> func_id/service entry (as needed)imports: symbol refs -> relocation slots
-
Implement a linker that:
- builds a
ProgramImagefrom N modules - resolves imports to exports
- produces a single final
FunctionTableand code blob
- builds a
Notes
- VM does not do name lookup at runtime.
- Linking errors are deterministic:
LINK_UNRESOLVED_SYMBOL,LINK_DUP_EXPORT, etc.
Tests
- two-module link success
- unresolved import fails
- duplicate export fails
Acceptance
- Multi-module PBS works; “import” is operationalized correctly.
PR-11 — Canonical integration cartridge + golden bytecode snapshots
Why: One cartridge must be the unbreakable reference.
Scope
-
Create
CartridgeCanonical.pbsthat covers:- locals
- arithmetic
- if
- function call
- syscall clear
- input snapshot
-
Add
goldenartifacts:- canonical AST JSON (frontend)
- IR Core (optional)
- IR VM / bytecode dump
- expected VM trace (optional)
Tests
-
CI runs cartridge and checks:
- no traps
- deterministic output state
Acceptance
- This cartridge is the “VM heartbeat test”.
PR-12 — VM test harness: stepper, trace, and property tests
Why: Industrial quality means test tooling, not just “it runs”.
Scope
-
Add
VmRunnertest harness:- step limit
- deterministic trace of stack deltas
- snapshot of locals
-
Add property tests (lightweight):
- stack never underflows in verified programs
- verified programs never jump out of bounds
Acceptance
- Debugging is fast, and regressions are caught.
PR-13 — Optional: Refactor Value representation (tagged slots) for clarity
Why: If current Value representation is the source of complexity/bugs, refactor now.
Scope (only if needed)
-
Make
Slotexplicit:Slot::I32,Slot::I64,Slot::U32,Slot::Bool,Slot::ConstId,Slot::GateId,Slot::Unit
-
Multi-slot types become sequences of slots.
Acceptance
- Simpler, more verifiable runtime.
Work split (what can be parallel later)
- VM core correctness: PR-01..PR-08 (sequential, contract-first)
- Debug + tooling: PR-09, PR-12 (parallel after PR-03)
- Linking/imports: PR-10 (parallel after PR-01)
- Canonical cartridge: PR-11 (parallel after PR-05)
“Stop the line” rules
- If a PR introduces an opcode without stack spec + verifier integration, it’s rejected.
- If a PR changes bytecode layout without bumping version, it’s rejected.
- If a PR adds a feature before the canonical cartridge passes, it’s rejected.
First implementation target (tomorrow morning, start here)
Start with PR-02 (Opcode spec + verifier) even if you think you already know the bug. Once the verifier exists, the rest becomes mechanical: every failure becomes actionable.
Definition of Done (DoD) for PBS v0 “minimum executable”
A single canonical cartridge runs end-to-end:
letdeclarations (locals)- arithmetic (+, -, *, /, %, comparisons)
if/elsecontrol flowwhenexpression (if present in lowering)- function calls with params + returns (including
void) - multiple return slots (flattened structs / hardware value types)
- host syscalls (e.g.,
GfxClear565,InputPadSnapshot,InputTouchSnapshot) - deterministic traps (OOB bounded, invalid local, invalid call target, stack underflow)