Solver and numerical methods
The numeric solver paths implement root finding, numerical differentiation, integration, and time-value-of-money calculations. Each path repeatedly evaluates an expression through the calculation engine and the TI-BASIC interpreter.
Raw opcode checks supply banked-page evidence where Ghidra does not recover a complete function body.
Solver errors [confirmed]
The numerical routines raise four dedicated errors. Each has a tiny page-0 raiser stub
that loads an error code into A and tail-jumps to _JError (ram:2793); most banked
pages also keep a local copy of each stub so the iteration loop can reach it with a
cheap relative jump.
| Error | bcall | page-0 stub | code | Message |
|---|---|---|---|---|
_ErrSignChange | 0x44C5 | ram:2749 → _JError(0x98) | 0x98 | NO SIGN CHNG |
_ErrIterations | 0x44C8 | ram:274D → _JError(0x99) | 0x99 | ITERATIONS |
_ErrBadGuess | 0x44CB | ram:2751 → _JError(0x9A) | 0x9A | BAD GUESS |
_ErrTolTooSmall | 0x44CE | ram:2755 → _JError(0x9C) | 0x9C | TOL NOT MET |
error_name_table (07:6B81) is indexed by
(code − 0x88), so codes 0x88…0x9C map to consecutive strings:
07:6B81 SYNTAX(88) DATA TYPE(89) ARGUMENT(8A) DIM MISMATCH(8B) INVALID DIM(8C)
UNDEFINED(8D) MEMORY(8E) INVALID(8F) ILLEGAL NEST(90) BOUND(91)
WINDOW RANGE(92) ZOOM(93) LABEL(94) STAT(95) SOLVER(96) SINGULARTY(97)
NO SIGN CHNG(98) ITERATIONS(99) BAD GUESS(9A) STAT PLOT(9B) TOL NOT MET(9C)
SOLVER=0x96 is the context name shown on the Solver app’s error screen;
SINGULARTY=0x97 is raised when a step lands on a pole. [confirmed]
Equation Solver and solve( root finder [confirmed]
The interactive Equation Solver app and the numeric solve( token share one
root-finding engine living on flash page 0x39. (The Solver app’s UI — the
EQUATION SOLVER / eqn:0= / bound= / left-rt= screen — is drawn from strings at
06:6ABB, loaded by code at 06:6286/06:62EA/06:66F3.)
Function-value evaluator f(x) [confirmed]
A callback, given the trial value in OP1, returns f(x) = left − right
of the equation. Located around 39:468F:
-
_CkValidNum(ram:1E9B), then_MovFrOP1(ram:1B0C) stores the current guess into the solve variable (its data pointer is loaded from(9306), in the expression-stack region — the bytes areED 5B 06 93=LD DE,(9306)). -
It installs the error handler at
39:46C7, then re-evaluates the stored equation throughparse_inp_current_state_bjump(ram:391B). The stub’s inline descriptor targetsparse_inp_current_state(38:5992), an interior entry in_ParseInpthat preserves the already selected parser state. -
The error filter at
39:46C7inspects the error code inA: codes below0x86(OVERFLOW/DIV BY 0/SINGULAR MAT/DOMAIN) and0x87(NONREAL ANS) are swallowed by these comparisons:CP 0x87 JR Z CP 0x86 JP NC,0x2799This
xis treated as a point wherefis undefined, so the solver can step past it, while0x86(BREAK) and codes≥ 0x88are re-raised via_JErrorNo(JP 2799). Before returning a swallowed error,fix_temp_count_bjump(ram:327F) dispatches to_FixTempCnt(07:4FEC) to repair temporary-object accounting. This is whysolve(can skip singularities inside the bracket without aborting. [confirmed]
The sign test 39:463A reads OP1.value.type (8478) and OP2.value.type (8483), masks 0x80
and XORs them: Z = same sign, NZ = opposite sign — the bracket sign-change predicate. [confirmed]
Iteration loop [confirmed]
Setup (39:43AD…4410) evaluates f at the two user bounds, records their signs, and
seeds the bracket. The main loop runs from 39:4413:
- Loop / iteration counter is carried in
A,INC Aeach pass (39:44BF), pushed on the stack. Two caps are compared withSBC HL,…:LD HL,0x01F3(=499) at39:4479/39:458B→ exceeding it jumps to39:45A0 LD A,0x99 … JP 2793= ITERATIONS, and the earlyLD A,0x9Apath (39:45AD) = BAD GUESS (raised when the initial bracket is unusable).- A small count (
CP 0x04,39:44C3) gates the early Illinois/secant correction.
- Bisection midpoint:
_InvSub(ram:227D, = b−a) then_TimesPt5(ram:2382, ×0.5) give the half-width $\tfrac{1}{2}(b-a)$ at39:443C/443F; adding $a$ yields the midpoint $m=a+\tfrac{1}{2}(b-a)$. [confirmed] - Secant / regula-falsi step:
_FPMult(238B),_FPSub(2297),_FPDiv-class and_InvOP1S(24BD) around39:4488…44F2compute the linear-interpolation step $x_{n+1}=x_n-f(x_n)\,\dfrac{b-a}{f(b)-f(a)}$. The result is compared against the bisection bound; the algorithm keeps the secant guess only if it stays inside the bracket, otherwise it falls back to the midpoint — a classic bisection ⊕ secant (Illinois/regula-falsi) hybrid, the documented TI behavior. [standard] - Sign-change bookkeeping: the byte at
0x84AF(OP6 area) holds the running sign offat the bracket ends;XOR 0x80toggles it (39:44AB…44B3). If the two bounds never bracketed a sign change, the path at39:45CD…45DA JP 2749raises NO SIGN CHNG. [confirmed] - Convergence / tolerance test:
_AbsO1O2Cp(ram:1987, compares |OP1| vs |OP2|) is used repeatedly (39:446F,44D7,44F8,45C7) to test the bracket width / residual against tolerance.const_solver_tol_1e13(39:46EA) stores the1.0e-13tolerance;const_solver_floor_1e99(39:46E1) stores the1.0e-99(00 1D 10 …). On reaching tolerance the solver exits through the39:4540 → 4553branch (dynamically traced on anX²−2 = 0solve that converged to √2 ≈ 1.41421356);39:4547is aCALL, not the converged return, and the observed path bypassed it. The tolerance tests at446F/44D7/44F8run under that trace;45C7is reached only on other convergence sub-paths. [confirmed]
\begin{algorithm}
\caption{Solver root-finder --- bracketed secant / regula-falsi (page 0x39)}
\begin{algorithmic}
\REQUIRE bracket $[a,b]$ with $\mathrm{sign}(f(a)) \neq \mathrm{sign}(f(b))$ \COMMENT{else \textsc{no sign change} (0x98)}
\FOR{$k = 0$ \TO $499$}
\STATE $m \gets a + \tfrac{1}{2}(b-a)$ \COMMENT{bisection midpoint: \texttt{\_InvSub}, \texttt{\_TimesPt5}}
\STATE $s \gets a - f(a)\,\dfrac{b-a}{f(b)-f(a)}$ \COMMENT{secant: \texttt{\_FPMult/\_FPSub/\_FPDiv}}
\STATE $x \gets s$ \textbf{if} $s \in [a,b]$ \textbf{else} $m$ \COMMENT{fall back to bisection}
\STATE $f_x \gets \mathrm{eval\_equation}(x)$ \COMMENT{re-parse, error-trapped (39:468F)}
\IF{$\mathrm{sign}(f_x) = \mathrm{sign}(f(a))$}
\STATE $a \gets x$ \COMMENT{keep the sign change in the new bracket}
\ELSE
\STATE $b \gets x$
\ENDIF
\IF{$|b-a| < 10^{-13}$}
\RETURN $x$ \COMMENT{converged, exits via 39:4540 -> 4553}
\ENDIF
\ENDFOR
\STATE \textbf{raise} \textsc{iterations} (0x99) / \textsc{bad guess} (0x9A)
\end{algorithmic}
\end{algorithm}
Dynamic confirmation. Traced end-to-end under headless TilEm by driving the built-in Equation Solver to solve
X²−2 = 0(solver-sqrt2.macro). It converged on screen toX = 1.4142135623…(√2) withleft-rt = 0. The mem-write records show the guess at0x8478climbing1.40898 → 1.41421335 → 1.4142135623645 → 1.4142135623731(|err| ≈ 4.9e-15, crossing below the1e-13tolerance on the final step).solver_iterate(39:4413) ran 808×; the per-iteration re-parse (parse_eval_expr38:5AB3) ran 834×; the secant-in-bracket-else-bisect test (39:44F8), the499-cap compare (39:4479 LD HL,0x01F3), and the1e-13/1e-99constants (39:46EA/46E1) all executed as the pseudocode describes.
left-rt shown on the Solver screen is the final residual f(root) (the
left-side − right-side value the evaluator computed). [standard]
TVM finance solver [confirmed]
The five-variable time-value-of-money solver (N, I%, PV, PMT, FV, plus
P/Y, C/Y, and the PMT:END/BEGIN flag) lives on flash page 0x3A. Each variable is a
named system FP var; the routine loads them via small accessors:
3A:7F02loads the pointer at(84D3)(iMathPtr1;ED 5B D3 84=LD DE,(84D3)),3A:7F0Fthe one at(84D5)(iMathPtr2), etc. ((D?5B)are the finance sysvar VAT slots).(84D3)=iMathPtr1,(84D9)=iMathPtr4,(84AF)=OP6,(84D3)/(84D9)/(84D3)hold the iteration state. [confirmed]
TVM equation
The solver evaluates the standard cash-flow identity (rate $i = \tfrac{I\%}{100}\big/\tfrac{C}{Y}$, with $S=0$ for END / $1$ for BEGIN):
$$0 = PV + (1+iS)\,PMT\,\frac{1-(1+i)^{-N}}{i} + FV\,(1+i)^{-N}$$
Implemented with _FPRecip (ram:253D, for (1+i)^(−N) via reciprocal/power),
_FPMult (238B), _FPDiv (2541), _FPAdd (RST 30h), _InvSub/_FPSub
(227D/2297) around 3A:70D6…7140. The compound factor (1+i)^N is built with the
power/exp helpers. [standard]
Iteration [confirmed]
Solving for I% (the only variable with no closed form) uses Newton’s method on the
rate:
-
Iteration state is allocated as a small FPS frame at
3A:70A2:LD HL,0x0005 bcall(_AllocFPS)The loop counter is
B = 0x40(=64iterations max),3A:70AB. -
Each pass recomputes the TVM residual and its derivative, takes a Newton step, and tests the exponent of the correction against
CP 0x74(3A:71F4) — i.e. converged when the update is ≤ ~10⁻¹². The new estimate is written back via(84D9)→(84D3)(3A:71F9…71FE). [confirmed]
_SinH call in the TVM rate loop [confirmed]
At 3A:710B the TVM body contains EF CF 40:
RST 0x28
.dw 0x40CF
The bcall
table maps 0x40CF to _SinH (_SinHCosH=0x40C6, _SinH=0x40CF, _ASinH=0x40ED
are three consecutive distinct entries). A scan of the whole loop body (3A:70A0…7210) finds
three bcalls: _SinH (0x40CF, 3A:710B), an unmapped helper 0x462A (adjacent to
_AdrLEle 0x462D — a list/element accessor for the finance sysvar slots), and _SetXXOP2
(0x478F, 3A:71C5). The _SinH call carries the math: the surrounding
_FPMult/_OP1ToOP2/_FPSub sequence (CD 8B 23 … CD D4 16 CD 51 16 EF CF 40 CD 3F 16)
evaluates the annuity / compound-growth factor in hyperbolic form — the numerically
stable way to form (1+i)^N − 1 and [1−(1+i)^-N]/i for small rates i, avoiding
catastrophic cancellation. This is the only transcendental call in the rate-Newton loop. [confirmed]
- Exhausting the 64-iteration
DJNZ/DEC Bbudget falls to3A:7206 JP 274D= ITERATIONS (0x99). Solving forN/PV/PMT/FVis closed-form (algebraic rearrangement) and does not iterate. [standard]
The amortization helpers (ΣPrn, ΣInt, bal(, Pmt_End/Pmt_Bgn) and the finance
function tokens (tFinNPV 0x00, tFinIRR 0x01, tFinBAL 0x02, tFinPRN 0x03,
tFinINT 0x04, tFinPV 0x2D, tFinPMT 0x2E, tFinFPMT 0x20, tFinPMTend 0x4B,
tFinPMTbeg 0x4C; all 0xEF-prefixed 2-byte tokens) are dispatched into this page.
IRR( internally uses the same rate-Newton iteration and can also raise ITERATIONS. [hypothesis]
nDeriv( and fnInt( numeric calculus [hypothesis]
The numeric-calculus engine is on flash page 0x33 (the graph-math page — appropriate,
since both operate on a Y= expression). The function tokens are 0xBB-prefixed:
tRoot 0x22 (the solve(-style root token), tFnInt 0x24 (fnInt), and
tNDeriv 0x25 (nDeriv). They are recognised by the 0xBB-group scanners
(33:504E CP 0xBB, also 38:4E3F).
nDeriv( symmetric difference quotient [standard]
nDeriv(expr, var, value [,ε]) computes the centered difference
(f(x+ε) − f(x−ε)) / (2ε) with default ε = 1e-3. The setup region 33:4C80…4D00
stores/restores the variable, evaluates f at x±ε, and divides by 2ε using
_FPSub/_FPDiv (2297/2541) and _TimesPt5. The (97E7)/(97E9) counters at
33:4C80/33:4CB4 track the two/three sub-evaluations. The finite-difference
and variable save/restore flow is [confirmed]. The default ε is [standard].
fnInt( adaptive numeric integration [confirmed]
fnInt(expr, var, a, b [,tol]) is an adaptive iterative quadrature. The body is the
Ghidra function fnint_body at 33:4D00 (extent 33:4D00…4E91):
-
builds interval midpoints and half-widths:
_FPSub(2297),_TimesPt5(2382, ×0.5),_FPDiv(2541). The bytes at33:4D18are executable code —33:4D18 21 83 84(LD HL,0x8483),33:4D1B 3E 60(LD A,0x60),33:4D1D CD 65 1B(CALL fp_set_digit1B65; not_OP2SetA, whose body is1B24) — loading the scalar0x60 = 96(a working digit/scale count), not a quadrature weight. [confirmed] -
maintains a working set of partial sums in an FPS frame (
_AllocFPS 1534,_PopRealOx 14F6/150F/1505,_DeallocFPS 1526, with slot offsetsDE=0x15/0x1B/0x24) — endpoint values, the running estimate, and the previous estimate for the error test. [confirmed] -
iterates, refining the partition by interval bisection. The ×0.5
_TimesPt5halving refines the interval, the97E7/84AFdepth counters track subdivision depth, and the loop tail includes33:4E81 LD DE,0x0024 … C3 CB 45, while33:4E8C 3D F5 C2 57 4Ddecodes as:DEC A PUSH AF JP NZ,0x4D57It converges when the change in the estimate has exponent
≤ CP 0x74(~10⁻¹²,33:4E74). Exhausting the refinement budget falls through to33:4E8F JP 274D= ITERATIONS (0x99). [confirmed]
Quadrature rule. A full byte scan of 33:4D00…4F00 finds exactly one
floating-point constant in the body: const_ln10x100 (33:4E92)
(00 82 23 02 58 50 92 99 40 = 2.30258509…×10², i.e. ln(10)·100). It is referenced at
33:4E5D:
LD HL,0x4E92
CALL 0x1982
This is immediately after the only transcendental bcall in
the body, 33:4E56 EF AB 40 = bcall _LnX (0x40AB). So ln(10)·100 is used purely to
convert the requested significant-digit tolerance into a decimal error bound via
ln — it is a tolerance scaler, not a quadrature node or weight. There is no node/weight table anywhere in
the body (the data after 33:4E92, FD CB 18 AE …, decodes as code: RES 5,(IY+0x18)
followed by LCD/keypad port I/O DB 3A / D3 3A). A Gauss–Kronrod rule would require a fixed
block of ~7–15 irrational node and weight constants stored as TIFloats; their complete
absence, together with the explicit ×0.5 interval bisection and the coarse-vs-fine estimate
comparison, rules out Gauss–Kronrod. The rule is an adaptive Newton–Cotes-style scheme
with recursive interval bisection (Simpson-class), not Gauss–Kronrod.
[confirmed] The only constant present is the ln-based tolerance scaler; no
quadrature node table exists.
Both nDeriv( and fnInt( evaluate the user’s f by storing the running argument into the
integration/derivative variable and re-running the parser, exactly like the Solver’s
f(x) callback — the same “store var → parse_eval → read OP1” loop. [standard]
Parser feedback loop [standard]
Every routine above shares this inner cycle, which is the whole reason they are slow:
- Place the trial value in
OP1(_Mov9ToOP1/ arithmetic result). _MovFrOP1(ram:1B0C) store it into the named variable the expression mentions (the solve var, thenDeriv/fnIntintegration var, or the TVM var).- Re-evaluate the expression through the TI-BASIC parser (
_ParseInp 38:5987/parse_eval_expr 38:5AB3/_Find_Parse_Formula 38:758A; the Solver uses its ownparse_inp_current_stateentry at38:5992). The parser walks the same stored token stream each pass. - Read the numeric result back from
OP1, form the residual / difference, decide the next step. The error handler at39:46C7, its(IY+7).2state bit, and the_FixTempCntcleanup catch a DOMAIN/NONREAL error at one sample. The solver treats that point as undefined instead of aborting, as described under Function-value evaluator.
Because the expression is re-tokenised and re-evaluated on every iteration, a solve(
with a 499-iteration cap can parse the equation up to ~499 times, and a fnInt over a fine
adaptive partition can parse it thousands of times — the dominant cost.
Parser routing for tFnInt, tNDeriv, and tRoot [confirmed]
These three are 2-byte tokens with the t2ByteTok = 0xBB lead byte (ti83plus.inc:
tRoot = 0x22, tFnInt = 0x24, tNDeriv = 0x25), so in the token stream they appear as
BB 22 / BB 24 / BB 25. The routing is a generic paged command call, not an inline
bjump, and goes through the page-0x02 command-execution layer:
-
The evaluator hands the operand token to the page-0x02 dispatcher, which recognises the
0xBBgroup and the second byte:tFnIntat02:68F3(CP 0x24),tNDerivat02:6904(CP 0x25),tRootat02:58AD/02:69BC(CP 0x22). [confirmed] -
The page-0x02 handler parses the comma-separated argument list and sets defaults. For example, the
nDeriv/fnIntprologue at02:6AF6does:LD A,0x7D LD (0x8479),AThis seeds the default tolerance exponent
0x7D(=1e-3, the documented nDeriv ε) before the call. [confirmed] -
It then performs a paged call into page 0x33. The page-0x33 entry re-validates the token through the
33:504Ebb_token_scanner(CP 0xBB, thenCP 0x68 / 0xCF / 0xDB / 0xF6to assign a small class index inCandCALL 0x50AC) and dispatches into the numeric bodiesnderiv_body(33:4C80) /fnint_body(33:4D00). Because the call crosses pages through the bcall/app-call trampoline, no static xref to these bodies survives in the Ghidra database — the mark of a generic paged call rather than an inline bjump. [confirmed]
Routine index [confirmed]
Equation Solver / solve( (page 0x39):
39:43AD solver_root_setup (eval f at both bounds, seed bracket)
39:4413 solver_iterate (bisection+secant hybrid main loop)
39:463A solver_sign_test (OP1/OP2 sign-change predicate; Z=same sign)
39:468F solver_eval_fx (store guess -> reparse equation -> f=left-right)
39:46C7 solver_eval_errfilter (swallow <0x86 and 0x87/NONREAL; re-raise 0x86/BREAK and >=0x88 via _JErrorNo)
ram:391B parse_inp_current_state_bjump (cross-page stub to 38:5992)
38:5992 parse_inp_current_state (interior _ParseInp entry used with selected state)
ram:327F fix_temp_count_bjump (cross-page stub to _FixTempCnt at 07:4FEC)
39:46EA const_solver_tol_1e13 (convergence tolerance, TIFloat 00 73 10..)
39:46E1 const_solver_floor_1e99 (residual-zero floor, TIFloat 00 1D 10..)
39:45A0 ->ITERATIONS(0x99) 39:45AD ->BAD GUESS(0x9A) 39:45DA ->NO SIGN CHNG(0x98)
TVM / finance solver (page 0x3A):
3A:70A2 tvm_solve_iterate (Newton on I%, 64-iter FPS-framed loop)
3A:7F02 tvm_load_var (iMathPtr1) 3A:7F0F tvm_load_var (iMathPtr2) (finance var accessors)
3A:7206 ->ITERATIONS(0x99)
Numeric calculus (page 0x33):
33:4C80 nderiv_body (centered difference (f(x+e)-f(x-e))/2e, e=1e-3)
33:4D00 fnint_body (adaptive bisection integrator; extent 4D00..4E91)
33:4E56 ->bcall _LnX (0x40AB) (digit-tolerance -> decimal error bound)
33:4E8F ->ITERATIONS(0x99)
33:4E92 const_ln10x100 (TIFloat 00 82 23 02 58 50 92 99 40 = ln(10)*100; the
ONLY FP constant in fnint_body -- no node/weight table)
33:504E bb_token_scanner (CP 0xBB then class-index 0x68/0xCF/0xDB/0xF6 -> CALL 50AC)
33:4381 ctrlflow_handler_table (13-entry jump table for For/While/Repeat/End/Return, etc.)
33:435F ctrlflow_dispatch (entry from bcall 0x5140/0x513D; SUB 0x20; index the table)
Page-0 FPS register save/restore + active-frame bookkeeping cluster (the “solver helper
cluster” — these are generic FPS slot accessors used by the solver, fnInt/nDeriv and other
FPS-framed routines; each slot is 9 bytes = one TIFloat, offset -(9*slot) from the frame
base pointer (9302)):
ram:2800 fps_swap_active_frame (swaps the active FPS frame pointer at (86DE) -- the
bracket/scope bookkeeping primitive)
ram:2895/28C3/28D8/28E9/2903/2908/2914/291B fp_st_slotN_opX
(store OP1/OP3 into FPS slot 2/4/5/6/7/7/8/9)
ram:29CF/29D7/29DB/2A0B/2A0F/2A13/2A17 fp_ld_op1_slotN
(load OP1 from FPS slot 5/7/8/10/11/12/13)
Error stubs / table (page 0 & 0x07):
ram:2749 _ErrSignChange(0x98) ram:274D _ErrIterations(0x99)
ram:2751 _ErrBadGuess(0x9A) ram:2755 _ErrTolTooSmall(0x9C)
ram:2793 _JError 07:6B81 error_name_table (indexed by code-0x88)
Shared FP/parse helpers (page 0): _FPAdd 229E, _FPSub 2297, _FPMult 238B,
_FPDiv 2541, _FPRecip 253D, _InvSub 227D, _TimesPt5 2382, _InvOP1S 24BD,
_AbsO1O2Cp 1987, _OP1ToOP4 19EC, _OP4ToOP2 19FE, _CkValidNum 1E9B,
_MovFrOP1 1B0C, _AllocFPS 1534, _DeallocFPS 1526, _PopRealOx 14F6/150F/1505.
Parser entries (page 0x38): _ParseInp 5987, parse_eval_expr 5AB3,
_Find_Parse_Formula 758A.
Resolved behavior and remaining questions
Summary of the four sub-results:
-
fnInt(quadrature rule. Not Gauss–Kronrod. The body has no node or weight table; its sole FP constant isconst_ln10x100, used with bcall_LnXto convert digit-tolerance to a decimal error bound. With explicit ×0.5 interval bisection and a coarse-vs-fine estimate comparison, it is an adaptive Newton–Cotes / Simpson-class bisection integrator.33:4D1Bis executable code:LD A,0x60 CALL fp_set_digit -
TVM
_SinH(id0x40CF). The TVM rate loop calls_SinHat3A:710B(0x40C6/0x40CF/0x40EDare three distinct hyperbolic bcalls); it evaluates the annuity / compound factor in hyperbolic form for numerical stability at small rates. -
Class-3 routing of
tFnInt,tNDeriv, andtRoot. The parser route isBB-token → page-0x02 dispatcher (02:68F3/6904/58AD) → arg-parse + default-tol (02:6AF6, exp 0x7D = 1e-3) → paged call → page-0x33 bodies, re-validated bybb_token_scanner(33:504E). The trampoline hides the static xref, confirming it is a generic paged call. -
Page-0 helper cluster. The routine index identifies generic FPS slot save/restore (9-byte TIFloat slots at
-(9*slot)from frame base(9302)) plus the active-frame swapper atram:2800, renamedfps_swap_active_frame; the store/load stubs arefp_st_slotN_opX/fp_ld_op1_slotN.
Residual (genuinely unverified, would need deeper paged tracing):
- The exact byte layout of the For/While/Repeat loop-control record pushed by the
page-33 control-flow handlers (
ctrlflow_handler_table) is not yet field-mapped; only the dispatch path is confirmed. See the TI-BASIC execution pipeline. - bcall
0x462Ain the TVM body is unmapped (adjacent to_AdrLEle; likely a finance-sysvar list/element accessor).