The interpreter executed bc.t/bnc.t's delay-slot instruction on both the taken
and not-taken paths. On real i860 the ".t" conditional branches annul that slot
when NOT taken -- the compiler fills it with the loop body's first pointer load,
valid only when the branch continues:
xor 0,r4,r0 ; CC = (node == NULL)
bnc.t loop ; continue while node != NULL
fld.d 0x20(r4),f16 ; annulled when node==NULL; else reads *NULL
For cap7/trek/batest (<512 live objects) the stray reads land in dead registers,
so the bug stayed latent -- cap7's rendered coefficient stream is byte-identical
before/after this change (verified: md5 52e16774... over the first 3 draws). But
the same stray access corrupted the object-registry tail-find walk (REGISTER
@0xf04041f8) whenever the 512-bucket handle hash chained (>512 live objects),
orphaning entries so FIND_REMOTE missed -> NULL -> firmware exit()
("Attempt to add NULL to a list"). That killed every content capture
(fxtest/sdemo4/glblade) ~1/3 in, before any draw.
Fix: a _squash flag skips the delay slot (whole next pair in DIM) on a not-taken
bc.t/bnc.t. fxtest now replays all 18987 commands and emits 3.67M coefficient
words of real geometry (previously 0 -- it died at cmd 6277); cap7's full mission
is unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>