Fixes root cause B: a CPU bus cycle drives address+strobe then reads the
data bus in the same tickTimers call, so the memory chip must react before
the read. Phase 0/1 applied each net change by firing PinManager listeners
immediately, which recurses one JS frame per hop - deep glue chains are
deep recursion and a combinational loop overflows the stack.
- busKernel.ts: a delta-cycle settle loop. A net change is recorded in a
pending set, not applied recursively; settle() drains it in batches
(deltas), applying each and letting the driven chips re-dirty the next,
until a fixed point or DELTA_CAP trips (oscillation -> warn, not hang).
Two-phase: a drive lands in pending and is applied on the next delta, so
a chip evaluating mid-settle reads last-stable nets. The first drive of a
cycle settles synchronously before returning to the chip's C code, so the
in-cycle vx_pin_read sees settled data.
- busNets: publishes resolved levels through the kernel instead of calling
triggerPinChange directly.
Tests (chipbus-buskernel): multi-hop chain settles; settle-before-read; a
5000-hop chain settles without stack overflow; a ring oscillator trips the
cap and warns instead of hanging. The two-real-chip integration still
exchanges 0xA5 through the kernel. Full suite 2079 pass flag-off.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>