243 lines
5.3 KiB
Markdown
243 lines
5.3 KiB
Markdown
## 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_slots` on operand stack at `RET`
|
||
* VM pops frame and transfers return slots to caller
|
||
* Define return mechanics for `void` (`return_slots=0`)
|
||
|
||
### Deliverables
|
||
|
||
* `FunctionTable` indexing and bounds checks
|
||
* Deterministic traps:
|
||
|
||
* `TRAP_INVALID_FUNC`
|
||
* `TRAP_BAD_RET_SLOTS`
|
||
|
||
### Tests
|
||
|
||
* `fn add(a:int,b:int):int { return a+b; }`
|
||
* multi-slot return (e.g., `Pad` flattened)
|
||
* 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`
|
||
* Implement/confirm:
|
||
|
||
* `GfxClear565 (0x1010)`
|
||
* `InputPadSnapshot (0x2010)`
|
||
* `InputTouchSnapshot (0x2011)`
|
||
|
||
### Deliverables
|
||
|
||
* A `SyscallRegistry` mapping id -> handler + signature
|
||
* Deterministic traps:
|
||
|
||
* `TRAP_INVALID_SYSCALL`
|
||
* `TRAP_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
|
||
* 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 `ProgramImage` from N modules
|
||
* resolves imports to exports
|
||
* produces a single final `FunctionTable` and code blob
|
||
|
||
### 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.pbs` that covers:
|
||
|
||
* locals
|
||
* arithmetic
|
||
* if
|
||
* function call
|
||
* syscall clear
|
||
* input snapshot
|
||
* Add `golden` artifacts:
|
||
|
||
* 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 `VmRunner` test 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 `Slot` explicit:
|
||
|
||
* `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.
|
||
|
||
---
|
||
|
||
## Definition of Done (DoD) for PBS v0 “minimum executable”
|
||
|
||
A single canonical cartridge runs end-to-end:
|
||
|
||
* `let` declarations (locals)
|
||
* arithmetic (+, -, *, /, %, comparisons)
|
||
* `if/else` control flow
|
||
* `when` expression (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) |