Add if_call to src/runtime/interfaces.s as the single interface dispatch
trampoline: resolve the compile-time slot, refuse invalid targets, pass the
object pointer as self, and return through one synthetic address so nested
and recursive calls unwind. Prove it with a new x128 fixture covering
runtime-selected targets, nesting, recursion, preservation, fault paths, and
the hardware-stack floor.
src/common/interfaces.inc (new error codes), src/runtime/interfaces.s
(if_call, if_vec, if_self)tests/runtime/dispatch-test.s (new)scripts/build-dispatch-test.ps1, scripts/verify-dispatch-test.ps1 (new)docs/decisions.md (D143), docs/architecture.md (status, 7.5),
docs/memory-map.md (dispatch rows)planning/claims/E06-S02.mdbuild/vals + 4*index at run time and
dispatches slot 0 for three different values. Each target checks that A/X
is its own object pointer (impl_self_bad stays 0), and the fixture checks
A/X ids $A0/$B0/$C0, if_error, and SP for every iteration.impl_one -> impl_two -> impl_three and checks the accumulated result
$33/$31; phase 3 recurses 8 levels through if_call with the depth passed
as a frame argument and checks the count, 9 entries, and restored FRAME_SP;
phase 7 recurses 12 levels, checks 13 entries, and confirms rec_min_sp
stayed at or above FRAME_HW_MIN.if_error, unchanged TSX, unchanged FRAME_SP, both argument
bytes intact, unchanged $0314/$0315, and an unchanged I/D mask; the
fixture documents A/X/Y as scratch and if_error as the refusal signal.IF_ERR_NULL), a non-null object with no table
(IF_ERR_TABLE), and a zero slot entry (IF_ERR_ENTRY). Each refusal
leaves A/X=0 and C=1, changes no call counter (impl_calls), and leaves TSX
unchanged; a later dispatch still succeeds.FRAME_HW_MIN - 1, gets IF_ERR_STACK with A/X=0, restores SP with TXS,
verifies TSX equals the saved value, and dispatches successfully again.if_vec cannot straddle a page: src/runtime/interfaces.s asserts
<if_vec <> $FF.if_slot) and E04-S02
(software frames); both are complete. No other claim was active.if_call reuses construct.s's proven one-level synthetic return form
rather than adding a dispatch stack; each nesting level owns its own pair on
the 6502 stack.if_call; table emission and
concrete-to-interface conversion were not added here.C:\Program Files\cc65-snapshot-win32\bin and the
session prefixed PATH; VICE tools resolve through the test module.IF_ERR_ENTRY and IF_ERR_STACK, then if_call, if_vec, and
if_self.tsx (which sets X) followed by
cmp (which compares A); changed the comparisons to tsx/txa/cmp.FRAME_SP captured before the two
frame arguments were pushed; both captures moved to just before the
dispatch. Diagnostic MB_ADDR traps located both issues and were removed
before the final run.DISPATCH OK.scripts/verify-dispatch-test.ps1 (x128, fresh D81);
scripts/verify-interface-test.ps1 (regression after the interfaces.s
change); git diff --check.$2542; mailbox 4E 38 03 A5 00 00 with flags
01 at MB_DATA+0..+6; screen shows NOVA128 DISPATCH TEST and
DISPATCH OK. The interface ABI fixture still reports INTERFACE OK.if_call uses one shared if_vec, safe only because the
jump happens before a nested call can reuse it. Interface-typed arguments
and results are not yet emitted by the compiler (E06-S04/E06-S05), and
physical C128 testing remains P2 validation.Powered by TurnKey Linux.