Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TI-BASIC dynamic tracing

TI-84 Plus OS 2.55MP — feature deep dive.

TI-BASIC behavior in these notes is grounded by generated programs, headless TilEm runs, resolved instruction coverage, and screen captures. This page is the book-facing recipe for reproducing those traces; the lower-level tooling details live in tools/dynamic-tracing.md.

Fixture suite

The fixture generator emits readable source, token bytes, and .8xp link files:

tools/tibasic_samples.py --write-dir tools/tibasic-samples

The smoke runner executes the exported programs, records a GIF, extracts the final frame, resolves trace coverage through tools/tilem_trace_resolve.py, and checks each case’s expected anchors:

TILEM=~/Git/tilem-headless/result/bin/tilem2
tools/tibasic_smoke.py --tilem "$TILEM" --rom tools/rom.bin \
  --out-dir /tmp/tibasic-smoke-full

Use --case NAME to run a subset, and --keep-trace when the raw binary trace is needed for instruction-level inspection. The runner deletes trace files by default because several cases produce hundreds of MiB per run.

The full suite passed on 2026-06-07 with the command above against OS 2.55MP and the local patched TilEm runner. The output directory kept final PNGs, GIFs, and coverage text for all cases; raw trace files were deleted by default.

The current headless workflow relies on a local TilEm patch that loads command line .8xp files before the macro starts. Without that patch, load the target programs into calculator RAM first, then run the same macro and resolver steps.

Operation coverage

CaseProgram(s)Operations exercisedAnchor examples
helloHELLO.8xpClrHome, Disp, string scan, Doneeval_stmt_entry, _Disp
factorialFACTOR.8xpPrompt, scalar stores, For(/End, FP multiply_FPMult, _Disp
dataDATA.8xplist literal, SortA(, cumSum(, sum(store_list_elem, list_fold_dispatch
asmcallASMCALL.8xp + ASMRET.8xpBASIC Asm(prgmNAME) into AsmPrgm payload_ExecutePrgm, ram:9D95
asmbridgeASMBRIDG.8xp + ASMSIG.8xp + ZZBASIC.8xpASM return code through Ans, BASIC callback_OP1Set1, _StoAns, _AnsName, eval_eqn_recursive
asmreturnASMRTN.8xp + ASMVAL.8xpASM return value through Ans, then BASIC arithmetic_OP1Set2, _StoAns, _AnsName, _FPAdd
asmfindASMFIND.8xp + ZZFIND.8xp + ZZBASIC.8xpASM-side VAT lookup of a BASIC program without executing itram:9D95, findsym_scan, _Disp
asmparseASMPARSE.8xp + ZZPARSE.8xp + ZZBASIC.8xpASM parser-entry negative probe ending at ERR:INVALID_ParseInpLastEnt, _ParseInp, parseinp_find_setup
asmformulaASMFORM.8xp + ZZFORM.8xp + ZZBASIC.8xpASM formula-parser negative probe ending at ERR:UNDEFINED_Find_Parse_Formula, parse_init_findsym, findsym_scan
animtextANIMTXT.8xptext placement animation with Output(_OutputExpr, _Disp
graphvizGRAPHV.8xpgraph-buffer primitives and DispGraph_GrBufClr, _ILine, _IPoint, _PDspGrph
graphdfsGRAPHDFS.8xpgraph visualization from DFS topology_StoSysTok, _ILine, _IPoint, _PDspGrph
graphlistGRAPHLST.8xplist-driven graph visualization from edge/node coordinate listslist_var_index, _GetLToOP1, _ILine, _IPoint
callsubCALLSUB.8xp + SUBRT.8xpBASIC prgmNAME, shared globals, Returnstmt_eval_body_entry, call_eval_eqn_recursive
callabiABICALL.8xp + ABISUB.8xpBASIC subprogram ABI through Ans, scalar A, and list L1_AnsName, store_list_elem, eval_eqn_recursive
callstopCALLSTOP.8xp + STOPSUB.8xpBASIC subprogram Stop terminates the caller chainstmt_eval_body_entry, call_eval_eqn_recursive, _Disp
bigaddBIGADD.8xplist-digit arithmetic and carry propagationlist_var_index, _GetLToOP1, _PutToL, _FPMult
bigmulBIGMUL.8xplist-digit multiplication, nested loops, carry normalizationlist_var_index, _GetLToOP1, _PutToL, _FPMult
dfsDFS.8xplist-backed stack, nested While/If/Forblockmatch_end_else, parse_scan_tokens, eval_stmt_entry

The visualization cases also enforce visible output by thresholding the final frame and comparing it with the first recorded frame. ANIMTXT, GRAPHV, GRAPHDFS, and GRAPHLST must contain at least 100, 100, 200, and 200 dark pixels respectively, and must change by at least the same number of pixels from first to final frame. ANIMTXT must also produce at least five distinct captured frames. The smoke runner also checks named crop regions. Visual cases check home-screen text, graph labels, axes, circle arcs, and node/edge regions. Text/list cases check important final-screen lines such as HELLO, WORLD, factorial 120, DATA list outputs, BEFORE/CALLED/AFTER, SUB, big-integer digit lists, and the DFS traversal/visited-list output. ASMRTN checks the displayed 5, ABICALL checks the scalar line, mutated list line, returned Ans line, and Done, and CALLSTOP checks BEFORE, STOP, Done, and a bounded low-pixel region where caller text AFTER would appear. ASMFIND checks the wrapper’s BEFORE, AFTER, and Done output plus a bounded low-pixel region where an unexpected third line would appear. ASMPARSE checks the ERR:INVALID, 1:Quit, and 2:Goto error-screen regions. ASMFORM checks the corresponding ERR:UNDEFINED error-screen regions.

For the visual graph cases, the 2026-06-07 run measured 212, 619, 466, and 466 dark pixels, with matching first-to-final pixel changes.

Reading the evidence

Trace anchors prove control reached the relevant ROM path; they do not by themselves prove the final screen looked right. Use both the coverage file and the final PNG/GIF for display or graph claims. This distinction matters for GRAPHDFS, where _ILine and _IPoint coverage only proves drawing routines ran, while the final frame proves the graph-screen topology is visible.

For parser and calling-convention claims, prefer resolved coverage plus a narrow routine trace. For example, the BASIC subprogram case uses the private 38:691038:691438:778F body-evaluator path after the top-level homescreen parse has already seeded parser RAM. That is why the negative ASM-to-BASIC probes in TI-BASIC programming patterns are negative fixtures or probes: they reach useful ROM paths, but they do not display the target BASIC program.