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

MathPrint live editor and settled drawing

TI-84 Plus OS 2.55MP — from the gap buffer to settled pixels.

This page follows one edit through the MathPrint editor: the gap buffer, the record graph, marker rendering, the page 39 argument layout, and the settled drawing that reset-origin traces pin byte for byte. It continues Equation display (MathPrint), which defines the records, handlers, and cell geometry used here.

Live editor reconstruction

The coverage report in Equation display (MathPrint) says which observations support the recovered logic. This page changes viewpoint: it follows an edit from the gap buffer, through the record graph, and back to pixels. [confirmed]

Gap buffer and record regions

The four editor pointers describe two live byte ranges separated by unused space:

typedef struct {
    uint16_t top;       /* editTop: first address of the left segment */
    uint16_t cursor;    /* editCursor: one past the left segment */
    uint16_t tail;      /* editTail: first address of the right segment */
    uint16_t bottom;    /* editBtm: one past the right segment */
} MathPrintEditorGapPointers;

/* Logical payload = [top, cursor) followed by [tail, bottom). */

The record-region pointers form a second typed block. Fields that remain unresolved keep address-based names: [confirmed]

#pragma pack(push, 1)
typedef struct {
    uint16_t structural_begin;   /* 0x8DAF */
    uint16_t extended_leaf_end;  /* 0x8DB1 */
    uint8_t unknown_04[9];
    uint16_t leaf_begin;         /* 0x8DBC */
    uint16_t leaf_end;           /* 0x8DBE */
    uint16_t unknown_11;
    uint16_t active_leaf;        /* 0x8DC2 */
} MathPrintArenaState;
#pragma pack(pop)

The in-progress editor is a gap buffer. editTop (0x96F4) and editCursor (0x96F6) bound the left segment. editTail (0x96F8) and editBtm (0x96FA) bound the right segment. Moving across a structural object exposes the six-byte right-segment marker EF type id_lo id_hi EF 2D. An insertion at that boundary makes the metric walker enter 34:759C with its parsed pointer at editTail + 6. The comparison at 34:75A1 then returns Z, so 34:75A5 falls through. [confirmed]

The live expression graph spans two record regions. eqdisp_find_structural_record starts at mathprintArenaState.structural_begin and stops at mathprintArenaState.leaf_begin. 34:4AF0 advances by the structural record size. The child words after each 20-byte header remain record IDs. eqdisp_find_leaf_record starts its leaf-record walk at mathprintArenaState.leaf_begin. It normally uses mathprintArenaState.leaf_end as the boundary. Bit 2 of (IY+1) instead selects mathprintArenaState.extended_leaf_end. [confirmed]

eqdisp_substitute_active_leaf handles the active gap during that leaf walk. When the gap bit is set and the current record equals mathprintArenaState.active_leaf, 34:4ABF substitutes editBtm as the next record pointer. Every other leaf advances by its 19-byte prefix plus the payload length at +0x11. The active record’s logical payload is the concatenation of editTopeditCursor and editTaileditBtm. This explains why a RAM dump can hold structural headers below the entry, the active leaf in the gap, and later leaf records near the top of RAM. [confirmed]

Four reset-origin RAM snapshots pin the cursor-to-record mapping. The compact bytes and expected trees are in tools/oracles/mathprint/mathprint-editor-gap-oracles.json. Each reproduction uses key input only. [confirmed]

Editor stateActive leafLogical gap payloadCursor pathSparse-state SHA-256Cursor-off LCD SHA-256
Empty fraction numerator9cursor, EF 1Enumeratorbcabb3961e1f37fe21b4e66c8bbfffb9a3812a162324e85273fdeed0beccc019450e82a31ced68ed319a1c2e8d18d3e2d3813f097de8be9dc2a89d48289cc4c9
Integral upper bound after 21032, cursorupper bound1dab216a05a2604bdb51eaa8a347a881f4dcccb7c8f19965503d73812422f8d539b937b16e32e4e07f6ffc2d6e60842c0249fd51d3aa661b23af2d2cb8708cea
Fraction denominator nested in an integral body1532, cursorbody → denominator7da6d7fdbb5ea848dda0afb1105237280a06b6dff994879df0a8c0b63e1a5f101297c2562d7c2fac9612aad6fc2e829ecb8f487606da6a079fb7d49d1c4c64d9
Immediately after a completed integral7EF 22 08 00 EF 2D, cursorroot sequence after integral89dd708b40f3c77f2cb5392783256576be8f0014beea2b411b6ba860dd441ef480cc504e3a7c6c773906f1e64ca6916e48594fd0c66c946151b3bc9849647f64

The empty numerator keeps EF 1E in the right gap segment, while its sibling denominator leaf resides near the high-memory boundary. The nested case links integral body leaf 11 to fraction record 13, whose second child is active leaf 15. The completed-integral case moves the active gap back to entry leaf 7; its cursor follows the complete six-byte type-0x22 marker. These states show that the graph itself preserves the editable nesting. [confirmed]

decodeMathPrintEditorRam() translates both record walks and the active-leaf substitution. decodeEditorExpressionGraph() inserts a cursor at editCursor - editTop, after checking the native token and six-byte marker boundaries. It recovers the nested cursor path from record IDs and leaf bytes; the screenshots do not participate in the decode. [confirmed]

constructEditorExpressionProgram() translates the inverse path. It allocates the entry leaf at ID 7, the transient type-0x1F wrapper at ID 6, and the same structural and child IDs as the captured arenas. The cursor contributes a six-pixel cell at render depth zero and a five-pixel cell in a raised row. A cursor immediately before EF 1E reuses that token’s six-pixel empty-slot cell. The ordinary structural metric formulas then propagate the active leaf’s height, width, and baseline through every ancestor. [confirmed]

The structural word at +0x05 identifies the active one-based child along the cursor path. A completed template outside that path retains its last child. Containing leaves on the active structural path retain the descendant marker’s byte offset at +0x0F. The active gap also retains its pre-edit +0x0F and +0x11 words, so the cursor node carries those two state words explicitly. They cannot be recovered from the concatenated gap payload alone. [confirmed]

For all four states above, decoding RAM to a cursor-annotated expression and reconstructing it matches every record field by ID. Executing the reconstructed record program in the cursor-off phase also matches the complete 96×64 calculator screenshot bitmap. The hashes in the last column cover all 768 LCD bytes. [confirmed]

Ordinary token insertion

Ordinary token insertion follows 34:4775–47A4 into 34:4BB9–4C0D. The non-structural branch reaches the page-6 gap writer through 00:3699. 06:4341–4388 checks available space, stores the one- or two-byte packed token at editCursor, and advances the pointer. In the captured root-leaf transition, the write at 06:437A stores 32h at 9DE1h; 06:437C then changes editCursor from 9DE1h to 9DE2h. [confirmed]

tools/oracles/mathprint/mathprint-editor-mutation-oracles.json retains two adjacent pre/post transitions and one five-write sequence. Appending 2 after root token 1 changes the active payload from 31h to 31h 32h. Inserting 2 into an empty fraction numerator advances the right gap boundary past EF 1E, so the token replaces the empty slot. The fraction transition also shows that the type-0x20 record keeps EFh at +13h instead of recomputing that byte from the new 32h numerator. The editor AST therefore retains structural +13h state in addition to the active leaf’s +0Fh and +11h words. [confirmed]

The five-write sequence enters 08 08 31 09 09, the native bytes for [[1]]. Wrapper record 6 continues to point directly to leaf record 7; the live arena allocates no structural record. After the first and second writes, the decoder retains one and two unfinished list frames around the cursor. The first 09h closes the inner frame into a one-element list. The second closes the outer frame into a list whose element is that inner list. The settled type-0x2B matrix record belongs to the later dimensioned construction path, not these five live gap writes. [confirmed]

editorInsertPackedToken() consumes the decoded arena, writes the active leaf payload, and decodes the graph again. All five [[1]] transitions match the post-key cursor tree, every reconstructed record field, and the complete cursor-off 96×64 LCD bitmap. Directly appending the byte to the previous semantic tree would miss four of the five regrouping transitions. Cursor navigation is tested separately below. [confirmed]

Structural template insertion

Most structural insertions share the same transaction. A small type policy decides which packed token, if any, moves into a child and which child receives the cursor:

\begin{algorithm}
\caption{Insert a structural template}
\begin{algorithmic}
\STATE $rule \gets \operatorname{TemplateRule}(renderType)$
\STATE split the active leaf at the cursor on a packed-token boundary
\STATE consume one token on the right when $rule$ requires replacement
\STATE write placeholder \texttt{EF type 00 00 EF 2D} into the containing leaf
\STATE allocate the structural record and its ordered child leaves
\STATE patch the marker with the allocated record ID
\STATE distribute the left payload according to $rule$
\STATE select $rule.initialChild$ and install its gap payload
\STATE remeasure ancestors while retaining editor-only record fields
\end{algorithmic}
\end{algorithm}

The policy table makes the structural differences explicit. “Initial focus” describes blank insertion; leading, mid-leaf, and leaf-end cases can migrate payload or choose a different child as described below. [confirmed]

Source tokenTypeOrdered childrenInitial focus
EF2Eh0x20numerator, denominatornumerator
00B2h0x21enclosed expressionenclosed expression
0024h0x22lower bound, upper bound, body, variablelower bound
0025h0x23variable, body, evaluation valuevariable
00F1h0x24index, radicandradicand, with Ans as the index
00BFh / 00C1h0x25 / 0x26exponentexponent
00BCh0x27radicandradicand
EF34h0x28base, argumentbase
EF33h0x29variable, lower bound, upper bound, bodyvariable
00F0h0x2Aexponent; base precedes the markerexponent

The blank entry line stores a zero-byte active leaf. Its only semantic node is the cursor at byte offset zero; inactive empty leaves remain invalid. Selecting the n/d template supplies source token EF 2E. 34:5935 maps that token to type 0x20. [confirmed]

The insertion follows 34:473A, the depth gate at 35:7B37, and the type dispatcher at 34:5026. The fraction case at 34:51B8–51D4 calls 34:5467–547E, which writes EF 20 00 00 EF 2D before the allocator patches the structural record ID. In the reset-origin blank-root capture, the ROM allocates fraction record 8, numerator record 9, and denominator record 10. It advances the structural depth from zero to one and selects numerator record 9 as the active leaf. [confirmed]

editorInsertStructuralTemplate() consumes the decoded arena state because the semantic cursor tree does not contain the next record ID or structural-depth byte. For this capture, it produces EF 20 08 00 EF 2D, moves the cursor into the empty numerator, and creates an EF 1E token in both children. The decoded post-key tree, all five record headers, and the complete cursor-off LCD bitmap match the calculator. The constructor also returns that decoded arena directly, so a following translated edit does not need to import RAM again. [confirmed]

Fraction insertion exposes the four cursor classes most clearly:

Cursor state before insertionNew numeratorBytes retained after the markerSelected child
Blank rootEF 1Enonenumerator
After 11nonedenominator
Between 1 and 212denominator
Before 12EF 1E12numerator

The migrated leaf keeps editor-only header state: the leaf-end case retains word0F = 0 and word11 = 1. In a nested example, outer records 810 remain in place while the allocator appends fraction 11 and children 12 and 13; the left payload migrates to child 12, and structural depth advances from one to two. Rebuilding the semantic tree from scratch would lose these record identities. [confirmed]

Natural-input oracles cover all four cursor classes at the root and in both children of an outer fraction. In every case the translated cursor AST, record fields, ancestor metrics, and all 768 LCD bytes match the calculator. Deeper fraction positions remain open. [confirmed]

Integral, nDeriv(, summation, log-base, and the one-child forms join the shared marker path at 34:5057, then allocate at 34:4862–34:492B. One-child forms also pass through 34:5473 and 34:58A0. Multi-argument forms reserve their child IDs in the table order above, initialize every child with EF 1E, and select the first child. The three captured permutations therefore distinguish integral (lower, upper, body, variable), derivative (variable, body, value), and summation (variable, lower, upper, body). [confirmed]

Across these forms, blank and leaf-end insertion retain the payload to the left of the cursor; leading and mid-leaf insertion replace one complete packed token on the right. Root-level natural captures cover all four cursor classes and match the decoded cursor AST, every record field, and all 768 LCD bytes. The blank derivative variable is visually distinctive: it adds two pixels between the derivative fraction and body, repeats after the evaluation bar, and renders EF 1E as a solid five-pixel focus box. [confirmed]

The nth-root route is separate: 34:504F enters 34:51C0–51D9, then reaches 34:5473, 34:58A0, and the three-record allocator at 34:4862.

Blank-root insertion places Ans (72h) in the index child and EF 1E in the radicand child. The cursor enters the radicand. Leaf-end and mid-leaf insertion move the payload left of the cursor into the index. Leading insertion creates blank index and radicand children and enters the index. Leading and mid-leaf insertion replace the packed token immediately to the cursor’s right. tools/oracles/mathprint/mathprint-editor-structural-mutation-oracles.json captures the four states. The translated AST, every record field, and all 768 LCD bytes match their calculator states. [confirmed]

Source token F0h maps to postfix-power type 0x2A through eqdisp_source_type_table. The editor dispatcher enters 34:50EF–511D, then joins the shared marker and allocation path at 34:5057. Blank-root insertion supplies Ans (72h) as the base. Leaf-end and mid-leaf insertion bind the atom immediately left of the cursor. Leading insertion has no base and replaces the packed token immediately to the cursor’s right. [confirmed]

The leading state contains EF 2A id_lo id_hi EF 2D without a preceding base. It is valid while the editor gap is active, and the LCD draws the exponent cursor above an empty base position. The JavaScript graph uses an editor-only emptyPowerBase node for this state. Settled graph decoding continues to reject a postfix-power marker without a base. Four reset-origin captures cover every root cursor class and match the cursor AST, every record field, and all 768 LCD bytes. [confirmed]

When the gap precedes an existing structural marker, 34:58A0–58B4 inserts the new six-byte marker without consuming the old one. Seven natural captures apply the one-child, nth-root, power, log-base, integral, nDeriv(, and summation constructors before the same completed fraction. Each post-key root leaf contains the new marker followed by the original EF 20 id_lo id_hi EF 2D marker. The existing fraction record also retains its +05h child-selector byte. The cursor AST carries that byte as editor_child_selector, so later JavaScript mutations reconstruct the live arena rather than replacing it with the selector implied by a settled tree. All seven translated states match every record field and the complete cursor-off LCD bitmap. [confirmed]

The radical template supplies source token 00BCh; 34:5935 maps it to type 0x27. Insertion follows 34:473A, the depth gate at 35:7B37, and 34:4169 into the type dispatcher at 34:5026. The type-0x27 path calls 34:5037, 34:5473–547B, and the marker writer at 34:58A0–58B4 before 34:4862–491D allocates the structural record and its radicand leaf. [confirmed]

Blank-root insertion allocates radical record 8 and radicand record 9. The parent leaf receives marker EF 27 08 00 EF 2D; child 9 receives EF 1E, and the cursor selects that child. Leaf-end insertion retains the left payload before the marker. With a token to the cursor’s right, the ROM replaces one packed token with the radical marker. It does not move left payload into the radicand. The leading 12 capture therefore becomes radical → 2, while the mid-leaf capture becomes 1 → radical. [confirmed]

A fifth root capture begins with 3 L1 and places the cursor before the two-byte 5D 00 token. Radical insertion removes both bytes and produces 3 → radical. editorInsertStructuralTemplate() applies the same packed-token boundary rule. [confirmed]

Insertion into either child of an outer fraction allocates radical record 11 and radicand leaf 12. Numerator insertion replaces payload in leaf 9; denominator insertion replaces payload in leaf 10. The controller depth moves from one to two, and the cursor selects leaf 12. Blank, leaf-end, leading, and mid-leaf captures cover all four cursor classes in both children. [confirmed]

The allocator loads the entry-record pointer from 0x8DBC and invokes unnamed bcall ID 53ADh at 34:490034:4905. Initialization at 34:490834:4928 overwrites the new ID, type, parent, selector, and depth fields. It skips bytes +07h+10h and does not write +12h or +13h. Structural insertion therefore retains the byte that occupied +13h in the old entry record. Root insertion at a nonzero cursor offset retains the entry leaf’s first payload byte. Insertion at offset zero retains EFh because the new marker becomes the first payload unit. A nested insertion does not derive this byte from structural depth or from the active child. [confirmed]

Four additional captures begin with root token 3 and insert a second radical into the first radical’s radicand. Blank, leaf-end, leading, and mid-leaf cases cover every cursor class in that child. The new radical record retains 33h from entry record 7, including the blank case whose active radicand begins with EFh. A blank fraction inserted at the same position also retains 33h, which exercises the shared structural-allocation rule. [confirmed]

tools/oracles/mathprint/mathprint-editor-structural-mutation-oracles.json retains the five macro and trace hashes, both RAM states, sparse arena bytes, screenshots, and complete LCD hashes. [confirmed]

editorInsertStructuralTemplate() retains the old entry byte before reconstructing the arena. Across all 17 radical transitions, its cursor AST matches the decoded post-key tree, reconstruction matches every record field, and execution matches all 768 LCD bytes. The fraction discriminator has the same record and LCD parity. Seven additional transitions cover insertion before an existing fraction marker. Other deeper structural positions and structural-boundary navigation outside the fraction, integral, summation, nDeriv(, and log-base cases remain open. [confirmed]

Cursor navigation

Cursor movement is token movement until it reaches a structural boundary. At that point it becomes tree navigation:

\begin{algorithm}
\caption{Move the MathPrint cursor}
\begin{algorithmic}
\IF{a packed token exists in the requested direction}
  \STATE move the complete one- or two-byte token across the gap
\ELSIF{the cursor is entering a structural marker}
  \STATE select the first child for \textsc{right}, or the last child for \textsc{left}
\ELSIF{a sibling exists in the requested direction}
  \STATE commit the current child and select the sibling endpoint
\ELSIF{the cursor is inside a structural record}
  \STATE commit the child and return before or after the containing marker
\ELSE
  \STATE leave the root state unchanged
\ENDIF
\end{algorithmic}
\end{algorithm}

Ordinary in-leaf navigation uses the page-6 gap movers. LEFT reaches 06:4294–42C7 through 34:42B4 and 00:3B49; RIGHT reaches 06:42C8–4301 through 34:4193 and 00:367B. Both paths call 00:1FE7 so a two-byte native token crosses the gap as one unit. Structural record markers remain on separate page-34 paths. [confirmed]

tools/oracles/mathprint/mathprint-editor-navigation-oracles.json captures 12 with the cursor at the end, after LEFT places it between the digits, and after RIGHT returns it to the end. The middle state splits the logical payload into left byte 31h and right byte 32h; its cursor offset is one. Its active leaf width is 12 pixels, not 18: before existing payload the cursor overlays the following cell without adding width. At the leaf end, the cursor allocates a six-pixel cell and the width returns to 18. All three reconstructed record sets and complete cursor-off LCD bitmaps match their calculator states. [confirmed]

editorMovePackedTokenCursor() translates both directions and rejects a structural boundary rather than applying the ordinary token rule there. After the decoder emits a cursor inside a numeric run, the following digit begins a new atom before the two sides recombine around the cursor. [confirmed]

A structural marker occupies six bytes: EF type id_lo id_hi EF 2D. RIGHT immediately before the marker selects the first child at byte offset zero. LEFT immediately after the marker selects the last child at the end of its payload. Both paths store the marker’s starting offset in the containing leaf, set the structural record’s one-based child selector at +05h, and increment the controller depth. The RIGHT route follows 34:4193–419B, 34:41E6–41F5, and 34:4285–4290. The LEFT route follows 34:42B4–42BC and 34:4311–4338. [confirmed]

The entry routes commit the containing gap leaf before selecting a child. A leaf can temporarily hold the left-gap byte count at +11h. The commit restores the complete payload length. A summation followed by X enters its marker from the right with +11h = 6, then stores +11h = 7 while the cursor is in the summation. editorMoveCursor() performs the same restoration from the decoded payload length. [confirmed]

RIGHT at a non-final child endpoint selects the next child at byte offset zero through 34:4193–41D7. LEFT at a non-first child start selects the preceding child at its payload end through 34:42B4–42EA. Each route stores the old child endpoint in that leaf’s +0Fh word and updates the one-based selector. Ordinary movement within a child changes only the active gap split; its stored +0Fh word remains unchanged until a structural transition commits the endpoint. [confirmed]

RIGHT at the final child endpoint returns to the containing leaf immediately after the marker through 34:41DC–4245. LEFT at the first child start returns immediately before the marker through 34:42ED–430E. The containing structural record becomes the controller, and the depth decreases by one. At the root leaf’s outer endpoints, 34:41AE–41DF and 34:42C5–42CC return without changing the arena. [confirmed]

tools/oracles/mathprint/mathprint-editor-structural-navigation-oracles.json retains seven reset-origin traces. Each fraction direction has seven adjacent RAM states. The integral traces retain 11 RIGHT states and ten LEFT states. A depth-two fraction trace retains 11 RIGHT states. The summation traces retain 11 RIGHT states and ten LEFT states. Their 60 key transitions cover entry, ordinary child movement, sibling selection, nested entry and exit, structural exit, and root endpoint no-ops. editorMoveCursor() reproduces every controller, active leaf, cursor offset, payload, child list, +05h, +0Fh, and +11h transition. Its returned decoded arena feeds the next movement directly. All seven sequences reach every subsequent captured state without replaying a recorded result. [confirmed]

One additional natural trace walks completed nDeriv(X,X,1) and logBASE(2,8) templates in both directions. Its four sequences retain 30 RAM states and 26 adjacent key transitions. The nDeriv( traversal covers its atomic variable plus ordinary body and evaluation-value children. The log-base traversal confirms that navigation follows the native base/argument child order. For these four sequences, editorMoveCursor() also matches every layout word and the reconstructed LCD bitmap at each state. [confirmed]

A second natural trace adds both directions for absolute value, radical, $e^x$, $10^x$, nth-root, and postfix power. Its 12 sequences retain 66 RAM states and 54 adjacent key transitions. Together the two trace files cover 96 states and 80 transitions across 16 sequences. Root-level live navigation is therefore captured for every insertable structural type 0x200x2A. Type 0x2B matrices are assembled from bracket tokens in the editor rather than entered as a structural template controller. [confirmed]

One more natural trace walks [[1]] in both directions. Its two sequences retain 14 RAM states and 12 adjacent key transitions, including the endpoint no-ops. Moving across the five packed tokens relocates the semantic cursor outside the outer list, inside either list frame, and on both sides of the element. editorMoveCursor() decodes each post-move AST rather than replaying those shapes. [confirmed]

The depth-two fraction’s mirrored LEFT trace adds 11 states and ten transitions. It starts after the outer fraction, enters its atomic denominator, returns to the outer numerator, enters the inner fraction from the right, walks both inner children, and exits both controller levels before checking the root endpoint. [confirmed]

A mixed-controller trace walks a completed fraction inside a radical in both directions. Its 18 states and 16 transitions enter and exit a one-child radical and a two-child fraction at depth two, with geometry-first cursor placement at both marker boundaries. The extra navigation corpus now has 139 states and 118 transitions across 21 sequences. [confirmed]

The reducer decodes each TilEm PNG and compares its black expression pixels with the translated record renderer. Because the blinking cursor may be gray, black, or absent, it masks only the cursor-cell rectangles emitted from the decoded active leaf. All other 96-by-64 pixels must agree. Every state in all 21 sequences passes that independent screenshot comparison as well as the exact arena comparison. [confirmed]

The cursor cell changes live metrics when it moves within a child. Entering the nDeriv( evaluation value at its end expands that leaf from four to nine pixels and propagates the five-pixel increase through the structural record and its ancestors. Log-base applies the analogous propagation and shifts its argument when the base cell expands. The translated post-move construction pass reproduces those record updates while leaving the page-6-owned +0Fh and +11h gap words intact. [confirmed]

A cursor immediately before a fraction, nth-root, or postfix-power marker allocates a large or small cursor cell because those structures begin with geometry rather than a full-size operator cell. Other structural markers let the cursor overlay their leading operator. For postfix power, the base remains before the six-byte marker in the parent leaf. The decoded editor AST therefore keeps a cursor at that boundary inside the power base; placing it after the completed power would reconstruct the cursor six bytes too far right. [confirmed]

The integral variable child uses leaf render type 0x01. Its cursor remains at byte offset zero. LEFT from the root’s post-marker position enters that child at zero rather than at the payload end. A second LEFT commits offset zero and selects the body at its payload end. In the other direction, RIGHT from the variable’s offset zero commits its full payload length in +0Fh and exits the integral. The variable therefore has no separate pre-token and post-token cursor states. [confirmed]

A leaf containing only EF 1E is also atomic. The depth-two fraction trace enters the outer denominator at offset zero. RIGHT commits the two-byte payload in +0Fh and exits the outer fraction without exposing a cursor state after the empty square. This trace supplies the natural witness for 34:75BB fallthrough. [confirmed]

The type-0x29 summation traces combine both atomic forms in one four-child record. The variable child has type 0x01; the lower-bound child retains EF 1E; the upper-bound and body children contain ordinary digits. A trailing root X adds ordinary parent-leaf movement before or after the structural crossing. Both directions visit all four children. [confirmed]

The summation fill trace retains eight adjacent states from template insertion through structural exit. The new variable child begins as type 0x01 with an EF 1E payload. Inserting X reaches the type test at 34:479634:479B, commits the one-byte variable, and calls 34:4181 to select the lower-bound child automatically. Lower-bound, upper-bound, and body insertion remain in their current child. The following RIGHT commits that child’s payload length to +11h and either selects its sibling or exits the summation. editorInsertPackedToken() and editorMoveCursor() reproduce all seven transitions as one composable decoded-arena sequence. The sequence starts from the decoded arena returned by editorInsertStructuralTemplate() for a blank root rather than from the first recorded summation state. Each reconstructed state matches the calculator’s record fields and cursor-off LCD bitmap. [confirmed]

Deletion and structural collapse

Deletion distinguishes ordinary bytes from empty structural children:

\begin{algorithm}
\caption{Delete at the MathPrint cursor}
\begin{algorithmic}
\IF{the target is an ordinary packed token}
  \STATE remove the complete native token
  \IF{a non-root leaf becomes empty}
    \STATE install the empty-slot token \texttt{EF 1E}
  \ENDIF
\ELSIF{the target is an empty structural child}
  \IF{the record has one child}
    \STATE unwrap that child
  \ELSIF{the type is a fraction or nth root}
    \STATE promote the sibling payload
  \ELSE
    \STATE retain the blank child
  \ENDIF
\ENDIF
\end{algorithmic}
\end{algorithm}

The generic transition tests apply the same decoded-arena rules to types 0x200x2B, a six-child matrix, two-byte child tokens, and depth-two nested markers. The type-0x01 variable rule is also tested in the integral, nDeriv(, and summation child positions. Live root-level sequence parity now covers every insertable type 0x200x2A; all 16 added directions include exact layout-word and screenshot parity. One depth-two fraction RIGHT and one LEFT traversal are also captured. The two token-built matrix directions and both radical/fraction directions include the same exact parity. Matrix deletion, row/column edits beyond the captured one-cell stream, and other deeper structural combinations remain open. [confirmed]

DEL removes the packed token at the right edge of the gap through 34:4570, 00:3687, and 06:4393–43A4. 06:43A5 reads the token and calls 00:1FE7; 06:439C advances editTail once for a one-byte token and twice when the classifier returns carry. Deleting 2 from the middle of root 12 therefore advances editTail from 0xFC44 to 0xFC45 without changing the cursor offset. [confirmed]

An empty active leaf takes the additional 34:4549–455B path. It inserts EF 1E through 34:4BB9–4C0D and the page-6 gap writer, then calls the LEFT mover so both bytes land in the right gap segment. The cursor remains at byte offset zero before the restored square. [confirmed]

tools/oracles/mathprint/mathprint-editor-deletion-oracles.json retains adjacent root and fraction-numerator deletion states. editorDeletePackedToken() produces both decoded post-key trees exactly, reconstruction matches every record field, and execution matches both complete cursor-off LCD bitmaps. The finite tests also delete a two-byte native token as one unit. [confirmed]

DEL on a structural child reaches 34:44F4. 34:47C7 checks that the active child contains only EF 1E and that the cursor precedes that token. 34:4504–450D then compares the child count at 0x8DBA with one. A one-child record reaches 34:4537, where 34:47FF removes the six-byte marker and the record with its direct child leaf. 34:453A–4544 rebuilds the parent layout and makes the containing leaf active. [confirmed]

Fraction type 0x20 and nth-root type 0x24 take 34:451F–4534 for either child. 34:452F XORs the one-based child selector with 3, which swaps child one and child two. The loop copies the sibling’s native payload into the containing leaf before it removes the wrapper. Deleting an empty numerator can therefore promote a denominator, and deleting an empty nth-root index can promote its radicand. The reverse directions promote the numerator or index. An EF 1E sibling contributes no bytes. [confirmed]

The other multi-argument types fail the 0x20 and 0x24 comparisons at 34:4513 and 34:4517. They fall through 34:451C to ordinary deletion at 34:456C, which leaves the empty-slot token unchanged. Integral 0x22, nDeriv 0x23, log-base 0x28, and summation 0x29 therefore retain a blank active child. [confirmed]

Schema 4 of tools/oracles/mathprint/mathprint-editor-structural-deletion-oracles.json retains nine live transitions. They cover both promotion directions for fractions and nth-roots, a blank radical, a power that retains its Ans base, and the protected integral path. editorDeleteStructuralTemplate() mutates the decoded record graph, then runs the graph decoder at the parent cursor position. All nine cursor trees, meaningful record fields, and complete 96×64 LCD bitmaps match the calculator. A finite dispatch test applies the classifier to blank insertion states for every type from 0x20 through 0x2A. [confirmed]

When deletion empties a leaf inside another structural record, 34:454D–455B checks the new controller type and inserts EF 1E. A fraction deleted from a radical radicand therefore restores a square in the radicand and leaves the cursor before it. The top-level type-0x1F wrapper returns at 34:4554, so a deleted top-level template can leave a zero-byte root leaf. [confirmed]

The ROM leaves EFh in physical byte +0x13 when the resulting active payload is empty. That byte lies outside the logical payload. Other nested deletion states, matrix type 0x2B, and structural-boundary deletion remain open. [confirmed]

34:759C–75A5 first subtracts six from its record pointer and compares that source pointer with editTail. Only equality reaches 34:789A. That helper tests bit 0 of tblFlags; when the bit is clear, it forces NZ, and when the bit is set, it preserves A while testing cxCurApp against kYequ (49h). A zero result therefore requires both the bit and the Y= application. Natural RAM and screenshot captures show the bit set while the inverse-video = field is selected. [confirmed]

Y= selection state

The Y= editor stores a one-byte selection-field prefix at editTail, then advances the page-6 record source past it. The first compared source pointer is therefore editTail + 1; later records advance farther through the bounded edit buffer. The short X^2 selection trace enters both metric passes with editTail = 0xFC9A and source pointer 0xFC9B. An overflowing six-power expression enters 12 times with source deltas 1, 9, 17, 25, 33, and 41 in each of its two passes. Selecting = on an empty expression makes no metric call. These three captures are recorded in tools/oracles/mathprint/mathprint-yequ-selection-oracle.json. Thus a valid state that makes 34:789A return Z has already failed the pointer guard, and 34:75A9 taken is infeasible under this entry invariant. The JavaScript translation retains the raw early-return path for byte-level routine parity. [confirmed]

When the Y= selection guard is false, 34:75AB reads the marker type from editTail + 1. 34:40F9 groups fraction (0x20), nth-root (0x24), and power (0x2A) markers; 34:75B0 takes its Z branch for this set. 34:75B8 then reads the nesting counter at 0x8515, and 34:75BB distinguishes zero from nonzero depth. tools/macros/mathprint-power-boundary-insert.macro reproduces the top-level power-marker path. The mixed radical/fraction trace naturally exercises 34:75B0 fallthrough. Both depth-two fraction directions naturally exercise 34:75BB fallthrough at nonzero depth. The RIGHT fraction trace remains the first report witness for the latter. [confirmed]

Record-oracle coverage

The record-oracle corpus contains 114 captured cases and includes every type from 0x1F through 0x2B. Types 0x200x2B have decoded record nodes and complete accepted-write oracles. The type-0x1F case is the transparent one-child wrapper described below: it has a captured node, child write stream, and pixel-exact entry screenshot, but it emits no primitive of its own. This saturates the 13-type record-node domain, not the internal branches of every handler. [confirmed]

eqdisp_draw_marker_primitive has two distinct entry ABIs. Render-table row 0 in eqdisp_render_handler_table (34:6119) contains the bytes 43 61, the pointer 6143h. _LdHLind at 00:0033 executes the following sequence:

LD A,(HL)
INC HL
LD H,(HL)
LD L,A
RET

Its low-byte load therefore makes a type-0x1F table dispatch enter eqdisp_draw_marker_primitive with A=0x43. That value follows the fixed default path to the seven-row bitmap at 34:61BE; (IY+44h).3 and 0x8520 do not affect this ABI. [confirmed]

Shared marker rendering

The editor calls the same helper through a different route. 06:7F29 loads editTail, 06:7F2D reads the marker type at editTail + 1 into A, and 06:7F2E calls the bjump descriptor at ram:30BD. Its bytes CD 09 2B 43 61 74 select 34:6143. The radical-marker trace enters with A=0x27 and (IY+44h).3 set, selecting the bitmap at 34:630C. The integral trace enters with A=0x22 and emits display code 0x7C. The reproductions in the coverage table use tools/macros/mathprint-radical-nonspecial-insert.macro and tools/macros/mathprint-integral-boundary-insert.macro. Absolute value, $e^x$, $10^x$, log base, and summation add live paths for A=0x21, 0x25, 0x26, 0x28, and 0x29. The editor marker domain also includes the exceptional 0x2C marker produced by the EF36h synthetic state. The default bitmap path handles it. [confirmed]

34:4FD9 allocates type 0x1F as a transient one-child root record. 34:6028 loads A=0x1F, and 34:602B calls 34:7844 to store the current render type at 0x8DE7. The following jump to eqdisp_render_child1 (34:636C) renders child 1 without using eqdisp_render_handler_table. A natural matrix-entry capture contains wrapper ID 6 at 0x9DB7 and child leaf ID 7 at 0x9DF9. Executing the captured graph through the JavaScript walker reproduces its 76-by-10-pixel entry image with zero differences. The wrapper contributes no pixel operation; all 175 accepted writes come from its child program. [confirmed]

The JavaScript record walker therefore keeps the two ROM-proven ABIs separate. A one-child type-0x1F node follows the natural eqdisp_render_child1 continuation. A childless node models the independent eqdisp_render_handler_table entry and its row-0 bitmap. No retained natural trace combines 0x8DE7=0x1F with 34:610534:6143, so the latter remains a decoded table ABI without a natural record dispatch. [confirmed]

settledSharedMarkerPrimitive() translates every conditional at 34:6143–61BD. Its finite test enumerates all 256 values of A, both states of (IY+44h).3, and all 65,536 values of 0x8520 when A=0x2B. Values of 0x8520 are irrelevant for other A values. The resulting 33,554,432-state projection has 14 path classes and 26 branch outcomes. [confirmed]

For the type-0x2B matrix marker, a nonzero high byte at 0x8521 or a low byte at or above the active bound emits display code 0x7C and sets (IY+32h).2. The bound is six when (IY+44h).3 is clear and eight when it is set. A smaller low byte emits 0xC1 when that flag is set. When it is clear, the helper emits the five-row bitmap at 34:61C7 and clears (IY-1).0. Retained natural traces do not yet exercise the four matrix-only conditionals at 34:617834:618E. [confirmed]

The object walker calls the post-render tail at 34:61CE with the current record type in A, the handler’s one-based child selector in E, and the structural nesting counter at 0x8515. Types 0x21, 0x27, and 0x2B always join 34:79C9 and decrement that counter. Type 0x22 decrements for child 3 or later; types 0x24 and 0x28 decrement for every child except child 1; type 0x23 decrements only for child 2; and type 0x29 decrements only for child 4. Every other type/child state preserves the counter. The decrement is byte-sized, so zero wraps to FFh. [confirmed]

settledRenderNestingTail() translates the returned A, complete conditional path, and counter transition. A raw interpreter executes the pinned bytes at 34:61CE34:6209 and 34:79C9 for every type/child byte pair against four counter values, then checks every counter byte on one decrementing and one preserving path. The symbolic model partitions all $256^3=16{,}777{,}216$ type, child, and counter states into 15 paths. Natural traces cover every conditional outcome except the type-0x2B branch at 34:61E2; its behavior is established by the pinned byte interpreter and finite transition model rather than claimed as a natural witness. [confirmed]

Page 39 layout control remains incomplete. Its class and handler tables, argument order, row composition, descriptor mapping, and draw paths are decoded. The browser-side ROM engine now translates the 39:4A74 token/action dispatch and its IY+2 exponent-context and IY+9 fraction-context class adjustments through editorTokenDispatch(). It returns the measured-template handoff at 39:672E separately from normal 39:4C27 handler lookup. [confirmed]

Page 39 maps the current token class to a handler recipe, selects a visible argument window, and emits its cells. When scrolling needs the neighboring named operand, saved OP identities feed the alphabetic VAT search rather than a parser-stream scan. [confirmed]

The editorArgumentClamp(), editorRowFromArg(), and editorLayoutArgument() translations cover the arithmetic at 39:50CF, 39:5101, and 39:513E: argument-count clamping, six-row window origin, seven-row mapping, and restoration of the caller’s baseline row. The cross-page continuation after 39:50CF remains caller state. [confirmed] The editorSubexpressionWindow() and editorSubexpressionCell() helpers translate 39:4C5A and 39:4CA4: they compute the visible slot, select the 984A or caller-supplied cell base, and retain styled-argument and empty-menu cross-page exits as explicit states. [confirmed] editorAdvanceArgument() and editorRetreatArgument() translate the forward and reverse slot branches at 39:5167 and 39:523B. They distinguish list endpoints, one- and two-row movement, subexpression fallback, both styled scroll directions, and the saved-F2 search’s carry exit. The forward two-row path compares 0x844B with 6 at 39:5181; the reverse path compares it with 3 at 39:5244. These jumps reach 39:4C5A before the styled-record test. Calls into scroll helpers remain explicit effects. The saved-operand wrappers derive their alphabetic outcomes from one shared VAT state. A missing VAT state stops at the saved-F2 search instead of selecting a scroll branch. The increment-wrap guard cannot execute: its preceding unsigned predicate requires a nonzero count and an index at most count - 2. [confirmed]

Alphabetic VAT selection

The saved-operand wrappers at 39:5B1039:5B44 move nine-byte operand buffers through OP1 at 0x8478. The E7 wrappers restore from 0x85E7; the F2 wrappers restore from 0x85F2. Each restore uses _Mov9B at 00:1A92. The ascending wrappers then call 39:59E0; the descending wrappers call 39:59F9. Bit 5 of (IY+11h) gates the entire wrapper. A clear bit preserves the incoming carry and performs no copy or search. With the bit set, search carry returns without writeback. Carry clear copies OP1 back to the selected source: 39:5AD2 writes 0x85E7, and 39:5B08 writes 0x85F2. The page-7 search receives the restored OP1 and the current VAT state. The styled overflow path applies the F2 writeback before it restores and searches E7. A raw-byte interpreter covers all 4,096 wrapper, gate, derived-carry, and buffer-source combinations. It also covers every value in every restored byte and every value in the seven selected payload bytes written back to a saved operand. [confirmed]

These page-39 buffers contain the nine identity bytes copied by _Mov9B. Their restore and writeback operations leave OP1+9 and OP1+10 untouched. The page-7 entry at 07:50BE copies all 11 bytes from OP1 to OP3 through 00:1A0F. Candidate construction starts by clearing all 11 bytes of OP2 at 07:51ED; 07:522E then copies the byte immediately below the selected VAT record to OP2+9 at 0x848C, while OP2+10 remains zero. The full-register copies through 00:1AE7 and 00:1A4E return those values in OP3 and OP1. Failure instead restores both incoming extension bytes from OP3. The translation and its raw wrapper oracle model this 11-byte behavior while the saved E7/F2 slots remain nine bytes. [confirmed]

The local dispatcher below those wrappers is translated separately by editorAlphaSearch(). 39:59E0 and 39:59F9 first call 39:5A17, which tests whether 0x85DE is class 0x02. The ascending class-2 path enters 39:59AF, emits 0Dh through RST 28h, and seeds OP1 with 14h at 39:59C6. The descending path enters 39:59B6, scans the eight payload bytes at 0x85E7+1 through 39:5A2E, emits 0Ch, and conditionally calls 39:1BAF when the emitter leaves carry set before the same 14h seed. [confirmed]

For other classes the ascending and descending paths execute XOR A, then cross to 00:3A53 and 00:306F, respectively. The fixed-bank stubs reach 07:50B5 (_FindAlphaUp = 4A44h) and 07:50B8 (_FindAlphaDn = 4A47h). Both bcalls take the current variable name in OP1. They return the selected variable in OP1 and OP3 and its VAT pointer in HL; carry reports that no matching entry remains. Carry clear then calls 39:5C2E; only class 0x03 with subclass byte 0x01 enters 39:1942. A = 06h repeats the alphabetic search, while every other value returns with carry clear. The JavaScript model derives each result from OP1 and a logical VAT snapshot. It derives the post-search A from the selected OP1 type, so a protected-program entry repeats without an injected return sequence. Nested and multi-argument states can therefore exercise the search without replaying an LCD stream. The page 39 control flow and bcall identities are [confirmed]. The page 07 inputs, outputs, and flag behavior are [confirmed].

editorFindAlphaVat() translates the selection state over an explicit logical VAT snapshot. Each snapshot entry contains its nine-byte OP-format identity, the byte immediately below its record, its VAT type-byte address, and its data-page byte. 07:50BB loads A = 00h, discarding the caller’s value; 07:510407:511D always compare the normalized type class. [confirmed] 07:5247 maps protected programs to the program class, complex lists to the list class, type 0x0B to equation class 0x03, and types 0x18/0x19 to class zero. [confirmed] The comparator at 07:5199 subtracts eight name bytes from OPx+8 down to OPx+1. Borrow propagation makes OPx+1 the most-significant alphabetic byte. The scan retains the nearest name above or below the incoming OP1, independent of physical VAT entry order. It returns the selected identity plus the two extension bytes in OP1 and OP3, its VAT pointer in HL, and carry at an alphabetic endpoint. [confirmed]

The decoder at 07:51BE rejects a first name byte below 41h or equal to 72h. It also handles list prefixes 3Ah and 5Dh 40h through MenuCurrent, inGroup, and bit 0 of (IY+0). While inGroup is set, an archived candidate uses its page byte for the final 41h/72h gate. OP1+2=FFh is the ascending-start sentinel at 07:5151; it admits every filtered Up candidate and makes Dn return carry. [confirmed]

Before comparison, 07:50C407:50F7 chooses the VAT region and clears unused key bytes. Program-like named types, names beginning with 5Dh, and List/CList keys beginning with FFh use the named region. Other List/CList forms, including 72h and 3Ah, use the fixed-token region. The fixed path preserves three name bytes and clears the remaining five. The named path clears bytes after the NUL-terminated name length; the one-byte 5Dh prefix has comparison length two. A failed search restores the complete original, unpadded OP1 from OP3. [confirmed]

Success returns A = 00h, Z set, and carry clear. Failure restores all 11 incoming bytes to OP1/OP3 and returns A = FEh, Z clear, and carry set. [confirmed]

editorDecodeAlphaVatSnapshot() builds the logical snapshot from a 64 KiB RAM image. The initializer at 07:50BE07:50F9 chooses one of two regions. Named/list-name searches start at progPtr and stop at pTemp; fixed-token searches start at symTable and stop at progPtr. [confirmed]

For a type cursor H, both entry forms store T2 at H-1, version at H-2, data address low/high at H-3/H-4, and page at H-5. A fixed entry stores three name bytes at H-6H-8 and advances to H-9. A named entry stores its length at H-6, name bytes downward from H-7, and advances by 7+length. The 72h and 3Ah forms use the fixed three-byte step. Type 09h decodes a fixed comparison key but uses the variable-length step at 07:512C07:5149. [confirmed]

editorForwardOverflowCue() and editorReverseOverflowCue() translate the closed cue routines at 39:66FE and 39:66E9. The reverse routine subtracts the selected argument at 0x85E0 from the count at 0x85E2 with byte arithmetic. A result below 8 returns without drawing. Other results place display code 0x1F at column 1 and row (winBtm - 1) & 0xFF. The forward routine places 0x1E at row 1, column 1. Both routines restore the word at 0x844B after their display call; the reverse early return leaves it untouched. A raw-byte interpreter exhausts all 65,536 count/index pairs and every winBtm byte. [confirmed] editorFirstArgumentAction() and editorAdvanceAction() compose those walkers with actions 0x03 and 0x04. They preserve the zero-count 256-iteration loop, byte-wrapped first-slot arithmetic, the one-call action-0x04 branch, and the flag-controlled tails. The tests exhaust all 65,536 count/index byte pairs for both values of bit 0 in each outer controller. The walker tests separately exhaust its layout-class and row predicates. [confirmed] The retained corpus observes 255 of 1,098 declared editor branch outcomes. It does not translate every key-to-graph mutation, cursor action, menu, error, or row-composition path. The live RAM decoder covers a complete captured graph; it does not predict the next graph from an arbitrary key action. [confirmed]

Accepted LCD-write parity is a separate result. The translated cases compare every synchronous accepted data write, including writes that leave the byte unchanged. Timer-interrupt run-indicator writes stay outside the MathPrint parity surface. A matching byte stream proves the tested construction and draw path; it does not close an unobserved editor or parser branch. [confirmed]

From live editor state to settled drawing

Trace provenance and scope

Two reset-origin TLMT v2 traces use the pinned ROM SHA-256 7d9a7d96d89fc552ebee6afdbdd011fdc6047be9c16d308245dff07eb1f7bd6d. The raw traces remain outside the repository because they are 162 MB and 202 MB. tools/oracles/mathprint/mathprint-trace-report.json records their hashes, emulator provenance, exact entry counts, state bytes, and replay results. [confirmed]

web/mathprint/draw-order.json preserves the visible pixel mutations after the final expression key press. The filled-integral trace contains 351 accepted LCD writes that change 522 pixels; the nested trace contains 391 writes that change 610 pixels. This sequence includes both set and clear transitions, so the interactive preview can replay the controller’s write order instead of an inferred glyph order. [confirmed]

ScenarioPage 0x39 editing hitsFinal stateSettled LCD replay
int(1,2,X^2,X)4CA4 ×1, 4DCA ×2, 4DE6 ×1, 4E8E ×7, 4F1A ×140x85E1=04, 0x85E8=0043×20; zero pixels differ from the model.
int(1,2,(1//2)X,X)The same handler entries, plus 683D ×5, 68AE ×1, and 69C8 ×10x85E8=10, 0x85EB=06, 0x85EE=02, 0x85EF=0247×23; zero pixels differ from the model.

Both traces execute eqdisp_emit_subexpr2 at 39:4CA4, not the static multi-argument entry at 39:5167. The nested case also executes the descriptor cell mapper and geometry selector, confirming that handler-record emission and descriptor geometry compose in one rendered expression. Neither trace reaches the exact entries 39:5167, 39:5949, 39:5B10, 39:5B1D, or 39:6ABF. [confirmed]

Settled render dispatch

For either a live-editor or settled redraw, page 34 walks the arena recursively. The live path first substitutes the active gap payload through eqdisp_substitute_active_leaf. A leaf then executes its token-and-marker payload; a structural record delegates placement to the handler for its type:

\begin{algorithm}
\caption{Render an arena record}
\begin{algorithmic}
\STATE $record \gets \operatorname{ResolveRecordId}(id)$
\IF{$record.type < \mathtt{0x1F}$}
  \STATE $\operatorname{ExecuteLeafProgram}(record.payload, origin, depth)$
\ELSE
  \STATE $handler \gets \operatorname{StructuralHandler}(record.type)$
  \STATE $\operatorname{RenderPlacedChildrenAndPrimitives}(handler, record, origin, depth)$
\ENDIF
\end{algorithmic}
\end{algorithm}

The settled walker dispatches object kinds 012 through the word table at 34:7012. The handlers are 34:6D0C, 706A, 70B8, 702C, 7133, 70A0, 70E2, 70E2, 7087, 7102, 717E, 70C1, and 71C6, in order. Kinds 6 and 7 share 34:70E2. The nested trace also visits transient records near 0xFBDB and 0xFBEF, so the final RAM dump does not contain every walked record. [confirmed]

These page 39 entries occur before the final GRAPHVAR key press. The settled redraw after that key does not re-enter them. It calls 34:6D26 and 34:737A from 34:4347 and 34:434A, then traverses the display objects from 34:6016. [confirmed]

For the nested scenario, tools/ti84re/mathprint/analyze_draw_trace.py attributes all 391 visible-changing writes after the final key. The nearest page 34 frames are 34:5FE7ram:34E9 (158 writes), 34:6CA8ram:3CE1 (96), 34:5DA2ram:3573 (78), 34:5EA3ram:3567 (24), and 34:5DBAram:3579 (10). The remaining 25 writes precede the page 34 object traversal and come from the large-font path. The fixed-page stubs dispatch to page 04 line and point routines and page 01:6297 small-font output. [confirmed]

Point and line primitives

A structural handler emits local points or axis-aligned lines. The shared drawing backend then applies four stages in order:

  1. Add the word-sized logical record origin.
  2. Subtract the horizontal or vertical viewport clip.
  3. Add the byte-sized physical screen origin and reject out-of-bounds points.
  4. Route each accepted point to the LCD, plotSScreen, or appBackUpScreen according to the destination flags.

The split between logical and physical origins is explicit in EqDispViewportState (0x8DFA): [confirmed]

#pragma pack(push, 1)
typedef struct {
    uint8_t physical_x;
    uint8_t physical_y;
    uint8_t right_bound;
    uint8_t bottom_bound;
    uint16_t logical_x;
    uint16_t logical_y;
    uint16_t horizontal_clip;
    uint16_t vertical_clip;
} EqDispViewportState;
#pragma pack(pop)

The point wrapper at 34:5E85 clips each object coordinate through 34:5DD1 and 34:5DEF. Its closed tail at 34:5E9834:5EA6 passes B=x, C=63-y, and D=1 to _PointOn at 04:4155. Dynamic samples include (x,y)=(3,0)BC=033Fh and (32,20)BC=202Bh. [confirmed]

_IPoint first supplies drawing-hook command 0 at 04:4158. An inactive hook preserves Z from the bit test and takes 04:4161 into the local point path. An active hook can return Z to request the same continuation; NZ restores the caller’s AF and returns without a local write. The translated dispatcher keeps the hook body as an explicit external boundary. [confirmed]

The local preprocessor then tests sGrFlags.g_style_active. Retained MathPrint calls have both the drawing hook and this style bit clear, so 04:4177 jumps directly to the coordinate path. That path adds the bytes at ram:8DA1 and ram:8DA2 to B and C, with byte wraparound, before checking the display bounds. apiFlg4.fullScrnDraw selects 04:4306, which admits $x$ bytes below ram:8DA4 and $y$ bytes below 64. Clearing the flag selects 04:42EC, which decrements the width bound and also rejects row zero. Both flag states occur in retained MathPrint traces. [confirmed]

The same translation covers the shared graph-style path rather than assuming that style state is always inactive. Style 1 at 04:4196 emits the current point and one to three neighboring attempts chosen from the unsigned current/previous coordinate relations. It stores the current B:C at ram:9315 for the next call. Styles 2 and 3 enter 04:40AD; the phase at ram:9668, step at ram:966C, style parity, and (IY+1Eh).7 select an aligned ascending or descending point sweep. 04:6F8404:6FAC initializes the phase modulo four, while the graph update path keeps the step in 13. Styles 0 and 4FFh emit only the original point. [confirmed]

settledPage4PointPipeline() processes every accepted expanded point in ROM order through the existing LCD/plotSScreen/appBackUpScreen byte router. This ordering preserves repeated visits to one byte instead of evaluating the expanded points independently. A pinned-byte interpreter agrees with the JavaScript preprocessor across 169,443 states: every input coordinate under both bounds helpers, offset and width boundary cases, all thick-point relation classes, every style-dispatch byte, and valid shaded phase/step samples. The symbolic report separately partitions all 512 style-dispatch states, all 33,554,432 effective-coordinate bounds states, all 4,294,967,296 thick-point coordinate relations, and all 3,145,728 graph-initialized shaded states at the 64-row limit. Arbitrary drawing-hook body behavior remains external. [confirmed]

04:42B504:42E3 converts the graph coordinate into the point mask, LCD commands, and buffer offset. It selects 80h >> (x & 7), uses x >> 3 as the byte column, and computes 3 * ((4 * display_row) & FFh) + byte_column. The row multiplication keeps its intermediate in one byte. Rows 40h7Fh therefore alias rows 00h3Fh before the column is added. _PointOn fixes D=1, so 04:424D04:4254 ORs that mask into the current byte. MathPrint’s wrapper clips to the 96×64 display before this entry. [confirmed]

The offset addresses plotSScreen at 0x9340 and appBackUpScreen at 0x9872. 04:424C04:42B4 maps D=0, 1, 2, and 3 to clear, set, XOR, and test. Test returns the masked bit without writing. The other modes route the resulting byte according to (IY+3Ch) and plotFlags.1 at (IY+02h). Bit 3 selects appBackUpScreen and bypasses LCD I/O. Otherwise, bit 0 selects the same direct-RAM route through plotSScreen. With both bits clear, the routine reads and writes the LCD. plotFlags.1 chooses the LCD byte as the source and preserves plotSScreen; clearing it selects and rewrites the RAM byte. Bit 2 mirrors the result to appBackUpScreen. [confirmed]

Retained MathPrint traces take the LCD route: (IY+3Ch) bits 3, 2, and 0 are clear, while plotFlags.1 is set. The translated renderer therefore reads the current LCD byte, applies the point mode, and emits the accepted controller write without modifying either RAM buffer. A raw interpreter checks all four modes, every source byte, all eight masks, every (IY+3Ch) byte, and both values of plotFlags.1. This covers 524,288 routing transitions in addition to the 8,192 isolated mode/mask transitions. [confirmed]

04:426B contains a controller-dependent workaround. When the hardware check returns NZ, byte column 5 and rows before command B7h force result bit 0 on the LCD write. The state transition exposes that condition explicitly. It does not apply the modified LCD byte to either RAM destination. [confirmed]

The JavaScript translation matches a raw interpreter of the pinned helper bytes for all 65,536 input-coordinate pairs. A second exhaustive comparison covers every previous byte for each visible coordinate: 1,572,864 point-on transitions. The wider diagnostic canvas used for overflow inspection can have coordinates above FFh; those pixels cannot enter the page-4 byte ABI and are kept separate from the physical LCD claim. [confirmed]

The line wrappers share eqdispViewport. eqdispViewport.physical_x is the screen $x$ origin, while eqdispViewport.logical_x is the record $x$ origin. eqdispViewport.physical_y and eqdispViewport.logical_y are the corresponding $y$ origins. Keeping those pairs separate matters in shifted editor modes even though all four values are zero on the normal home entry line. [confirmed]

34:5D96 passes a clipped vertical segment to 04:431D; eqdisp_draw_hline_clipped (34:5DA6) swaps the axes and passes a clipped horizontal segment to 04:4382. The nested trace’s fraction rule enters 34:5DA6 with object coordinates x=15, y=6 and origins x=16, y=5. Page 04 receives endpoints (17,52) and (21,52). [confirmed]

The callers supply ordered endpoints. The wrappers treat the two varying coordinates asymmetrically. An underflow of the first coordinate against the logical clip clamps to zero. A first coordinate at or beyond the exclusive screen bound returns without drawing. The second coordinate instead returns on underflow and clamps at bound-1 on overflow. 04:4379 performs the exclusive-bound test, while 04:43C0 selects the smaller ending coordinate. The JavaScript transition keeps the word-sized logical origins and clips separate from the byte-sized physical origins. [confirmed]

_DarkLine at 04:4025 fixes H=1 before entering _ILine at 04:4029. 04:404204:4069 computes the absolute byte deltas, direction bits, major axis, doubled minor increment, and signed error. 04:4078 calls _IPoint at 04:4157 before each step, so both endpoints produce writes. The major delta is incremented as a byte; a delta of FFh therefore produces 256 point visits. [confirmed]

A raw interpreter of the pinned _DarkLine bytes checks all 131,072 ordered endpoint pairs for horizontal and vertical lines. It also checks all 65,536 nonnegative delta pairs, which covers every major/minor ratio and signed-error sequence. Separate reverse-direction cases cover the direction branches. Physical MathPrint lines now compose this stepper with the translated point state transition. A hook-handled point remains delegated to the external hook body and produces no inferred local LCD write. [confirmed]

Word-sized geometry and clipping

The structural handlers retain coordinates and dimensions as 16-bit words. For example, 34:62B434:62C3 reads a radical child’s width word, increments DE three times, and passes the resulting word endpoint to 34:5DA6. 34:620A34:622C performs the corresponding word comparison for a fraction. The translated renderer therefore accepts widths beyond 255 and wraps additions at 16 bits before viewport clipping. A radical with record width 258 reaches a clipped vinculum from $x=-167$ through $x=87$ instead of rejecting the record as byte-sized geometry. [confirmed]

Structural render handlers

The dispatcher is easiest to read as a vocabulary of visual constructs. The paragraphs below retain the coordinate and trace details for each row.

TypeConstructHandlerDistinctive ordered output
0x20Stacked fraction34:620ANumerator, denominator, then a rule sized from the wider child.
0x21Absolute value34:6347Two vertical bars, then child 1.
0x22Integral34:622FInclusive stem and four hook points; child placement comes from the record.
0x23nDeriv(eqdisp_render_handler_tableDerivative fraction, body, variable, evaluation bar, then repeated variable and value.
0x24nth root34:6315Index, root hook and stem, radicand, then vinculum.
0x25 / 0x26$e^x$ / $10^x$34:6381Fixed glyph, then exponent child.
0x27Square root34:62A1Root hook and stem, radicand, then vinculum.
0x28logBASE(34:63B2Prefix, base, opening shape, argument, then closing shape.
0x29Summation34:6504Sigma/equals forms, children 1–3, then delimited child 4.
0x2APostfix power wrapper34:6375Recursively renders child 1; emits no primitive itself.
0x2BMatrix34:65AALeft bracket, row-major children, then right bracket.

Render-record type 0x22 dispatches through 34:6105 and eqdisp_render_handler_table to 34:622F. The word at record offset +7 is the integral-sign height $h$. The handler draws the inclusive stem (2,1)(2,h-2), then hook points (3,0), (4,1), (1,h-1), and (0,h-2), in that order. [confirmed]

Render-record type 0x20 dispatches to 34:620A. The handler renders child records 1 and 2 through 34:636C and 34:6378, then reads each child’s word at offset +7. It draws an inclusive horizontal line from (1,y) to (max(w_1,w_2)+1,y), where the parent word at offset +0x0B supplies $y$. The nested-fraction trace reaches the line wrapper with BC=1, DE=5, and HL=6, yielding (1,6)(5,6). [confirmed]

Render-record type 0x2A dispatches to a JP 34:636C at 34:6375. 34:636C selects child record 1 through 34:6CCD before entering the recursive renderer. The wrapper emits no point, line, or glyph itself. The corrected record-table trace identifies 0x2A as the X^2 root type. [confirmed]

Render-record type 0x27 dispatches to the radical handler at 34:62A1. It emits the ten-byte root-hook bitmap through eqdisp_draw_radical_hook (34:62D0), draws the vertical stem, selects child 1, and reads that child’s word at offset +7. It then draws the inclusive vinculum from (2,0) through (w+3,0) and renders child 1 through eqdisp_render_leaf_program. The cursor-free history redraw for sqrt(X^2+1) has height 8 and a child +7 width of 0x17. It reaches the wrappers with stem (2,1)(2,7) and vinculum (2,0)(0x1A,0). This produces the 26-pixel rendered width. The final editable-entry redraw has child width 0x1D and a vinculum endpoint of 0x20; cursor and edit-state geometry therefore remain separate from history-echo geometry. [confirmed]

Render-record type 0x21 dispatches to the absolute-value handler at 34:6347. The parent words at +7 and +9 supply height and width. The handler draws inclusive vertical bars at x=2 and x=w-4, then renders child 1 through 34:636C. The cursor-free abs(X-3) history redraw reaches the line wrapper with (x,y_1,y_2)=(2,0,6) and (0x1A,0,6). [confirmed]

Render-record type 0x24 dispatches to the nth-root handler at 34:6315. It renders index child 1, emits the root-hook bitmap at x=w_1-1, draws its short vertical segment, renders radicand child 2, and draws the vinculum. The cursor-free nthroot(3,X+1) history redraw reaches the wrappers with vertical segment (5,3)(5,4) and vinculum (5,2)(0x18,2). [confirmed]

The remaining settled render types map to calculator constructs through eqdisp_source_type_table and post-ENTER traces. Type 0x23 renders nDeriv(, 0x25 renders $e^x$, 0x26 renders $10^x$, 0x28 renders logBASE(, 0x29 renders summation, and 0x2B renders a dimensioned matrix. Type 0x1F is a transient one-child root type. The main draw entry at 34:6016 selects its child directly through 34:636C, so an ordinary history redraw does not dispatch that root through 34:6105. [confirmed]

Types 0x25 and 0x26 share the body at 34:6381. The handlers position and conditionally emit fixed display codes 0xDB and 0x1D, respectively. They then render child 1. The child record supplies its local origin through offsets +0x0B and +0x0D. [confirmed]

Type 0x28 dispatches to 34:63B2. It emits the three bytes returned by _KeyToString for 00C1h, renders child 1, emits the opening compound shape through 34:5D1A, renders child 2, and emits the closing compound shape through 34:5D07. The settled logBASE(2,8) root has child IDs 0x0010 and 0x0011. [confirmed]

Type 0x29 dispatches to 34:6504. It conditionally emits display code 0xC6, renders children 1–3, and surrounds child 4 with the compound emitters at 34:5D1A and 34:5D07. It also conditionally emits display code 0x3D between children 1 and 2. The settled sum(N,1,3,N^2) root contains child IDs 0x00140x0017. [confirmed]

Type 0x2B dispatches to 34:65AA. It emits the left vertical bracket and its two inward points, renders the matrix elements in child-ID order, then emits the right bracket and its points. 33:4F23 derives the element-loop bound from the dimensions at record bytes +0x12 and +0x13. The high byte at +0x12 stores the column count. Byte +0x13 stores the row count. A settled $2\times2$ identity matrix renders four children between the bracket operations. [confirmed]

Matrix layout

The type-0x2B constructor lays out elements in row-major order. For element width $w_{r,c}$, height $h_{r,c}$, and baseline $b_{r,c}$, define each column width, row baseline, descent, and height as [confirmed]

$$ \begin{aligned} C_c &= \max_r w_{r,c}, \\ B_r &= \max_c b_{r,c}, \\ D_r &= \max_c(h_{r,c}-b_{r,c}), \\ R_r &= B_r+D_r. \end{aligned} $$

The first column begins at $x_0=6$, and each later column begins after the previous extent and a six-pixel gap. The first row begins at $y_0=0$, and each later row begins after the previous extent and a two-pixel gap:

$$ \begin{aligned} x_{c+1} &= x_c+C_c+6, \\ y_{r+1} &= y_r+R_r+2. \end{aligned} $$

Each element is centered horizontally and baseline-aligned vertically:

$$ \begin{aligned} X_{r,c} &= x_c+\left\lfloor\frac{C_c-w_{r,c}}{2}\right\rfloor, \\ Y_{r,c} &= y_r+B_r-b_{r,c}. \end{aligned} $$

For $m$ rows and $n$ columns, let $N_e$ be the element count, $H$ the matrix height, $W$ the matrix width, and $y_c$ the vertical center:

$$ \begin{aligned} N_e &= mn, \\ H &= \sum_r R_r+2(m-1), \\ W &= 12+\sum_c C_c+6(n-1), \\ y_c &= \left\lfloor\frac{H}{2}\right\rfloor. \end{aligned} $$

The constructor stores $N_e$, $H$, $W$, and $y_c$ in the words at +5, +7, +9, and +0x0B, respectively. [confirmed]

Primitive matrix cells all have the same baseline, so they cannot distinguish baseline alignment from height centering. A mixed-height $1\times2$ trace does. Its first cell is 2//3^1, with $(h,b)=(16,6)$; the second is (1+3)*abs(2), with $(h,b)=(7,3)$. The row has $(R,B)=(16,6)$, so the calculator stores child origins 0 and 3. Height centering would place the second child at 5, producing 116 wrong pixels while retaining the correct 79-by-16 dimensions. The baseline formula reproduces the captured graph and all pixels exactly. [confirmed]

The word at +0x11 stores the column count in its high byte and structural depth in its low byte. The byte at +0x13 stores the row count. When the matrix contains more than one element, the allocation pass reserves the first child leaf and then leaves one unused ID before scanning that leaf for nested records. Primitive captures therefore have reachable child IDs 0x11, 0x13, 0x14, and so on when the matrix record is 0x10. A structural first cell uses 0x11 for the leaf, leaves 0x12 unused, and assigns its first nested record ID 0x13. [confirmed]

Five reset-origin traces cover primitive $1\times1$, $1\times2$, $2\times2$, $2\times3$, and $3\times3$ matrices; a sixth covers the mixed-baseline case above. The JavaScript constructor matches every captured record field, child ID, and element position. The matrix result begins at LCD row 9 and uses $x=95-W$, where $W$ is the outer leaf width at +7. The generated streams match 32, 46, 92, 134, and 180 synchronous accepted LCD data writes, respectively. [confirmed]

The $2\times3$ capture also contains eight accepted writes from the standard timer’s run-indicator handler at 01:6BBA01:6BFA. That handler reads and rewrites LCD byte column 11 across rows 0–7 through indicCounter and indicBusy at 0x8476/0x8477. Removing those asynchronous writes leaves the 134-write MathPrint stream. The generated timeline models the synchronous settled renderer and labels the interrupt writes separately in its oracle. [confirmed]

web/mathprint/rom-engine.js implements the complete 0x1F0x2B structural dispatch table as an executable record-graph walker. It resolves child IDs through a node map, adds each child record’s +0x0B and +0x0D origins on recursive entry, preserves the handler’s depth changes, and returns ordered primitive and leaf operations. A settled expression enters this layer from a type-0x00 leaf program at eqdisp_render_leaf_program. The program executor consumes its payload in order and invokes embedded structural records against the same pen and depth state. Row 0 uses the bitmap bytes at 34:61BE, as fixed by the table-load ABI; the captured type-0x1F wrapper instead uses the direct-child ABI above. The nDeriv( handler renders child 1 again at 34:64B3, then places display code 0x3D after that child’s +7 width. [confirmed]

Recovering semantic trees from records

A leaf is both text and a small program. Ordinary native tokens expand to display codes; embedded markers invoke structural records by ID without discarding the text on either side:

\begin{algorithm}
\caption{Execute a leaf record program}
\begin{algorithmic}
\WHILE{$pc < payloadEnd$}
  \IF{$pc$ names an embedded structural record}
    \STATE $\operatorname{RenderRecord}(\operatorname{ResolveRecordId}(marker.id), pen, depth)$
    \STATE advance past the marker
  \ELSIF{$pc$ is an embedded-object separator}
    \STATE advance past the separator
  \ELSE
    \STATE $(token, pc) \gets \operatorname{DecodeNativeToken}(pc)$
    \FOR{each $displayCode$ in $\operatorname{KeyToString}(token)$}
      \STATE $\operatorname{EmitGlyph}(displayCode, pen, depth)$
    \ENDFOR
  \ENDIF
\ENDWHILE
\end{algorithmic}
\end{algorithm}

The record graph is a layout program. The semantic AST is a second view decoded from ordered children, balanced native delimiters, and embedded-record markers. The live-editor path substitutes the active gap payload before this decode. Neither view is inferred from LCD pixels or screenshots. [confirmed]

The trace analyzer recovers leaf records from the resolver path. At 34:6CCD, DE is the one-based child index and ram:8DF2 points at the parent. At 34:6CD8, DE contains the selected child ID and HL points at its resolved record. Pairing these observations produces the complete record graph visited by a settled render. [confirmed]

Leaf payload begins at record offset +0x13; the word at +0x11 gives its byte count. A one-byte scalar therefore stores its display byte at +0x13. Compound leaf objects retain the subsequent bytes in the same record. A leaf may construct and dispatch another structural record while it renders. The analyzer preserves these secondary dispatches in instruction order. It uses the first eqdisp_render_leaf_program entry at the shallowest Z80 stack depth after the final key press to identify the enclosing leaf program. [confirmed]

The analyzer also decodes the reachable settled graph into a semantic expression tree. Structural child IDs recover argument order. A type-0x2A record binds its exponent to the expression immediately before the embedded-record marker. Balanced standalone 10h and 11h bytes become a group node, so a postfix power after the close binds to the complete group. The decoder advances over native two-byte tokens before interpreting grouping bytes. The pair 5E10h, for example, remains one token rather than opening a group at its low byte. The decoder preserves EF 1E as an explicit extended token. The renderer maps the pair to display code 0xF7, so the decoded tree exposes an unfilled template slot. The tree identifies the expression in a trace without using LCD pixels or a screenshot. It describes the settled graph consumed by eqdisp_render_leaf_program. The browser-side ROM engine exposes the same decoder for its generated AST view as settledAst. The live-editor wrapper applies this decoder after eqdisp_substitute_active_leaf substitutes the active gap payload, then inserts the cursor at the byte boundary selected by editCursor. [confirmed]

A structurally populated live matrix entry demonstrates why leaf decoding cannot treat every payload as a flat token sequence. Before evaluation, wrapper ID 6 points to a leaf whose payload begins 06 06 EF 27 08 00 EF 2D: the outer and first-row 06h containers precede an embedded radical record. The next element contains an embedded type-0x2A power marker. The decoder balances 06h/07h matrix, 08h/09h list, and function/group delimiters, splits only on depth-zero 2Bh or row-closing 07h, and resolves structural markers inside each cell. It recovers [[sqrt(2),X^2][3,4]] as a 2-by-2 matrix AST from the captured RAM. This raw-container representation is distinct from the evaluated type-0x2B matrix record, although both decode to the same semantic matrix shape. [confirmed]

Within that program, EF type id_lo id_hi invokes the structural record with the given little-endian ID. EF 2D terminates or separates the embedded object without drawing it. Ordinary payload bytes may follow. The settled sum(N,1,3,N^2) entry invokes type 0x29. Its body child emits N, invokes type 0x2A, and then closes the exponent object. This byte order matches the structural dispatch and glyph trace order. [confirmed]

executeSettledRecordProgram() translates this byte stream rather than replaying captured glyph events. Tests provide record headers, child IDs, and payload bytes as input. They compare the generated display-code, coordinate, depth, and order tuples with independently captured 34:6C37 observations for absolute value, summation with an exponent, and nested nDeriv(. [confirmed]

Glyph selection and hooks

The ordinary-token path resolves payload bytes through smallfont_glyph_ptr at 01:6702. A zero lead selects the word table at 01:4252. The two-byte leads 5Ch, 5Dh, 5Eh, 60h63h, 7Eh, AAh, BBh, and EFh select tables at 01:445201:47E8. The 5Eh second byte selects one of four banks. The BBh path clamps indices F6hFFh to F6h. [confirmed]

The raw D:E selector accepts more states than the native token grammar. Leads 01h5Ch alias the 5Ch table. Both 5Eh and 5Fh test index bits 4, 5, and 6 in that order, clear the first selected bit, and otherwise clear bit 7. Leads 64h7Dh and 7FhBAh alias the AAh table. Leads BChFFh alias the EFh table. _IsA2ByteTok prevents these extra aliases during ordinary token decoding. [confirmed]

01:6765 inherits Z from the preceding CP BBh; LD A,L does not change it. That JR NZ therefore falls through under the 01:6702 entry ABI. The CP 13h clamp at 01:677401:6778 has no other predecessor and is unreachable from this entry. A pinned byte interpreter matches the JavaScript table, normalized index, pointer-word address, and complete branch sequence for all 65,536 D:E pairs. [confirmed]

01:6788 skips the token hook when (IY+35h).0 is clear. When it is set, 01:7C53 classifies the Catalog2 hook header and version before the token-hook call. An invalid header returns C and Z, an older version returns C and NZ, the exact version returns NC and Z, and a newer version returns NC and NZ. Only the invalid-header class reaches 01:67AC: offsets through 0546h retain BC=0 and the offset in DE, while larger offsets pass the offset in BC and 000Ch in DE. [confirmed]

The page-3B wrapper at 3B:7B8D either enters the installed hook or clears (IY+35h).0 and returns to the ROM string. The finite model covers both flag values, four Catalog2 classes, all 65,536 offset words, and both wrapper outcomes. The installed hook body and any pointer or string that it returns remain external. [confirmed]

Each selected pointer names one metadata byte followed by a counted display-code string. Token 72h therefore expands to A, n, s. Token C2h expands to s, i, n, (. Two-byte token 5D 00 expands to L and the subscript-1 display code. _GetTokLen = 4591h reads the count, and _Get_Tok_Strng = 4594h copies the counted bytes. The browser uses the ROM-extracted tables in web/mathprint/token-strings.json; it preserves native token boundaries while constructing the settled record. [confirmed]

34:6873 receives each resulting display code. It diverts parentheses 28h and 29h, and braces 7Bh and 7Dh, to delimiter geometry. This includes 28h embedded in the spelling of sin(. 34:678C dispatches parentheses to 34:5D28 and 34:5D15, and braces to 34:5E0F and 34:5E14. The four paths emit points and lines instead of a large-font glyph bitmap. [confirmed]

Six reset-origin traces cover Ans+1, Ans^2, sqrt(Ans), X^Ans, sin(X), and sin(sqrt(X)). Their generated graphs match every record field. Their complete accepted-write streams contain 49, 40, 63, 32, 56, and 83 writes, respectively. Replaying each generated stream produces the same final 96×64 LCD bitmap as replaying its captured eqdisp_render_leaf_program interval. X^Ans verifies the variable-width small-font spelling. sin(sqrt(X)) verifies a counted token spelling before a structural child and the compound shapes around its taller metrics. The structural record stores the containing leaf’s accumulated horizontal anchor at +0x0D. [confirmed]

Five reset-origin traces cover L1, [A], Y1, Str1, and X^L1. Their generated record graphs match every field after normalizing record IDs. Their accepted-write streams contain 21, 35, 21, 42, and 22 writes. The generated stream and captured outer eqdisp_render_leaf_program interval have the same byte-column, row, and value for every write. Replaying either stream produces the same 96×64 LCD bitmap. X^L1 verifies two-byte spelling and width in the small-font exponent path. [confirmed]

The translated renderer then maps the ordered operations through the ROM font bitmaps, page-4 point and line behavior, _VPutMap, the page-7 large-glyph path, and LCD byte packing. Six settled programs reproduce every accepted LCD data write through the outer eqdisp_render_leaf_program return: absolute value (49 writes), nth root (69), radical (82), summation (66), nDeriv( (96), and a nested integral/fraction (114). This comparison includes accepted writes whose value does not change the displayed byte. [confirmed]

Compositional metrics

When a containing leaf appends a box with metrics $(h,b)$ to its current metrics $(H,B)$, the metric pass unions the extents above and below the baseline: [confirmed]

$$ \begin{aligned} B_{\mathrm{out}} &= \max(B,b), \\ H_{\mathrm{out}} &= B_{\mathrm{out}} + \max(H-B,h-b). \end{aligned} $$

The reset-origin expression ((1*A)/X)//(N-N)//(1*3)*((sum(X,2,1,N)*abs(3))/int(3,1,X,X)) combines an outer fraction with $(h,b)=(21,6)$ and a summation with $(h,b)=(19,9)$. Its live root record stores $(H_{\mathrm{out}},B_{\mathrm{out}})=(24,9)$. Maximizing the height and baseline independently would produce the incorrect height 21.

The small-font table at 03:4CD6 stores seven rows per glyph. _VPutMap emits the five interior rows. It retains an interior zero row, but it does not emit the padding row above or below the glyph. A row that crosses an LCD byte boundary writes the right byte before the left byte at 01:63CE01:641A. The large-font path emits all seven rows of its fixed cell. [confirmed]

34:6C3734:6CAB prepares two page-1 driver states. A root glyph uses the seven-row record built by 07:45B6. A raised glyph enters 01:6297 with a one-row source skip and a five-row count, so 01:635401:6374 advances past the first small-font padding row. The selected count also omits the trailing padding row. Vertical viewport clipping changes the skip and count before the page-1 call. [confirmed]

34:6C4D loads the width byte from the selected font record. When fontFlags.2 is clear, 34:6CBC adds three columns for display codes 28h and 29h, and two for 7Bh and 7Dh. Other codes retain the record width. The addition at 34:6C5A is byte-sized and can wrap. The translated metric and draw paths use this result for delimiter cells instead of a separate fixed width. Root calls set fontFlags.2 and retain the six-column large-font cell. Raised parentheses begin with width three and raised braces with width four; the correction expands both families to six columns. A pinned-byte interpreter covers both flag values and every display-code and width-byte pair. [confirmed]

The two states use different right-edge comparisons. The root state compares the endpoint with 0x61 at 01:630A, while the raised state compares it with 0x60 at 01:630E. CCF followed by JP C rejects endpoints at or above the selected limit. A root six-pixel glyph beginning at x=90 therefore draws through pixel 95. A raised four-pixel glyph beginning at x=92 is rejected as a unit. Pinned-byte differential tests cover all 3,584 pen-byte, width, and mode states plus all 112 width, bit-offset, and mode row states. [confirmed]

01:636001:6378 computes $8-o-w$, where $o$ is the LCD bit offset and $w$ is the glyph width. A nonnegative result selects the one-byte path. Its DJNZ entry arrangement rotates the screen byte by the remaining-space count, calls 01:6431, and reverses the rotation. A negative result selects the two-byte path, negates the value to obtain the overflow count, and circularly rotates the two-byte screen window. [confirmed]

The width-mask table at 01:6446 contains FE FC F8 F0 E0 C0 80. For an aligned screen byte $s$, mask $m$, and glyph row $g$, 01:643101:6445 computes $(s \mathbin{\&} m) \mathbin{\mathtt{xor}} g$ for ordinary text. When textFlags.3 is set, it computes $((\mathord{\sim}m) \mathbin{\vert} s) \mathbin{\mathtt{xor}} g$ instead. The translated composition matches a pinned-byte interpreter for all 917,504 screen-byte, width, glyph-row, and inverse-flag inputs. An independent row test covers 7,340,032 screen-window, offset, width, and inverse states, including both sides of every LCD byte boundary. [confirmed]

Absolute values, powers, and roots

The absolute-value constructor translates a closed slice of the earlier record pass. eqdisp_lookup_render_type maps source token 00B2h through eqdisp_source_type_table to render type 0x21. The translated 34:4900, 34:7393, and 34:7609 paths construct the containing leaf, the absolute-value record, its child leaf, and their settled metrics. Fresh reset-origin traces for abs(2), abs(X/2), and abs(X+12) match the generated record fields and every accepted LCD data write. The trace streams are comparison oracles and are not constructor inputs. [confirmed]

The compositional constructor translates the type-0x2A power and type-0x27 radical paths. eqdisp_lookup_render_type maps source token 00BCh through eqdisp_source_type_table to render type 0x27; the containing leaf embeds the structural ID and constructs the radicand as child 1. Its settled height, width, and baseline derive from the child metrics. Raised radicals select the final five rows of the root-hook bitmap at 34:62D0, while outer radicals use all seven rows. [confirmed]

eqdisp_lookup_render_type maps source token 00F0h through eqdisp_source_type_table to render type 0x2A. The containing leaf embeds EF 2A id_lo id_hi EF 2D, and child 1 contains the raised payload. The metric branches at 34:7393 and 34:7609 distinguish the first raised row from later raised rows. The JavaScript translation constructs right-associated record trees and obtains raised-glyph widths from the ROM small-font table. [confirmed]

Parentheses remain ordinary leaf tokens 0x10 and 0x11 in the settled record. 34:6873 maps their display codes 0x28 and 0x29 to the compound emitters at 34:5D1A and 34:5D07. A raised parenthesis keeps a six-pixel token-cell metric. The shape height and baseline follow the enclosed payload. The type-0x2A word at +0x0D stores the containing leaf width accumulated before the power object. It is 0x1E for (X+1)^2, after the five six-pixel leaf tokens, and 0x0C for the power inside (X^2+1). [confirmed]

Five reset-origin traces cover (X+1), (X^2+1), (X+1)^2, X^(1+2), and abs(X^2+1). The generated record graphs and complete accepted-write streams match these traces. The streams contain 49, 60, 59, 32, and 60 writes, respectively. [confirmed]

List braces remain leaf tokens 0x08 and 0x09; 0x2B separates elements. Their display codes 0x7B and 0x7D enter the same matching-delimiter scans at 34:689A and 34:6951 as parentheses. The final renderer uses the brace paths at 34:5E0F and 34:5E14. Each path emits two top points, an upper vertical segment, a waist point, a lower vertical segment, and two bottom points. The waist row equals the enclosed payload’s baseline. It can differ from the geometric midpoint. [confirmed]

Natural traces for {1,2} and {sqrt(2),1} pin the seven-row symmetric case and the nine-row case whose baseline is row five. The translated native parser retains element boundaries in a list node, including nested lists and structural elements. Both oracle bitmaps match the calculator pixel for pixel. Three seed-13 list-only differential cases add fractions, roots, variables, and ordinary operators; all three match their natural calculator screenshots. [confirmed]

When the immediate base of a power ends in a structural object, 34:70C17084 merges that object’s baseline and lower extent into the type-0x2A metrics. It does not use the containing leaf’s accumulated baseline: an earlier radical to the left does not raise a later plain-token power. [confirmed]

After the leaf obtains its merged baseline, 34:77AD77C1 revisits every directly embedded structural record. It subtracts the record’s baseline at +0x0B from the leaf baseline in ram:850A, then writes the difference at +0x0F: [confirmed]

$$ \mathtt{structure.word0F} = \mathtt{leaf.word09} - \mathtt{structure.word0B}. $$

For a trailing structural power base, the leaf baseline equals the power baseline. The value is therefore 3 for sqrt(X)^2 and abs(X)^2. A grouped fraction base has baseline 6 and lower extent 7; its outer power has baseline 12, height 19, and therefore stores 6 at the fraction’s +0x0F. The fraction’s visible numerator group requires two native 10h11h pairs: the fraction scanner consumes the outer pair and retains the inner pair in the numerator leaf. [confirmed]

For a grouped structural base, 34:70C1 saves the base baseline $b$ and lower extent $d$. After 34:7283 returns the raised child’s height $h_e$ in ram:8508, the handler stores [confirmed]

$$ \begin{aligned} b_p &= b + h_e - 2, \ h_p &= b_p + d. \end{aligned} $$

The reset-origin trace for (X^(X-2))^(N/X)^(N-3) gives the inner base $(h,b)=(10,6)$ and the outer power $(h_p,b_p)=(16,12)$. The inner type-0x2A record stores 6 at +0x0F. The translated record fields and final LCD pixels match the trace. The same rule at fraction depth gives inner $(h,b)=(8,5)$ and outer $(h_p,b_p)=(14,11)$. [confirmed]

Reset-origin traces for sqrt(X)^2, abs(X)^2, and abs(sqrt(X^2+1)) match every generated record field and accepted LCD data write. Their complete streams contain 35, 33, and 113 writes, respectively. The nested case verifies the absolute-value bars, radical hook and vinculum, powered radicand, and leaf glyphs in ROM emission order. [confirmed]

Fresh reset-origin traces for X^2, X^12, 2^X^2, and 2^X^2^3 match the constructed record fields and every accepted LCD data write. Their streams contain 17, 22, 22, and 32 writes, respectively. These captures test one, two, and three raised levels without supplying records or writes to the constructor. [confirmed]

Fixed-base exponentials and log base

The type-0x25 and type-0x26 constructors map source tokens 00BFh and 00C1h through eqdisp_source_type_table. Both allocate one exponent child. The child begins at x=6, uses raised small-font metrics, and determines the parent height, width, and baseline. The handlers at 34:637E and 34:63AD emit fixed large-font display codes 0xDB and 0x1D before rendering that child. The fixed symbol stays in the large font when the containing expression is raised. [confirmed]

For exponent metrics $(h,w)$ and render depth $r$, the shared metric path at 34:73DB produces [confirmed]

$$ H=h+4,\qquad W=w+6,\qquad B=\max(h,6[r>0]). $$

The six-row seed affects an exponential nested in a raised child. A reset-origin nDeriv(logBASE(1,2),X,e^2) trace stores $(H,W,B)=(9,10,6)$ for the type-0x25 record. Its containing evaluation-value leaf stores height 9 and baseline 6, which places the value at row 4 in the type-0x23 record. [confirmed]

Reset-origin traces for exp(12), exp(X^2), exp(1//2), and tenpow(X^2) match every constructed record field and accepted LCD data write. Each stream contains 22 writes. The JavaScript renderer generates the writes from the expression tree, constructed records, structural handlers, ROM font bitmaps, and LCD byte-packing logic. [confirmed]

The type-0x28 constructor maps source token EF34h through eqdisp_source_type_table and reserves the base and argument leaves before scanning either payload. 34:76A934:76BF decrements the structural-depth byte through 34:79C9. It places the base one pixel below the argument baseline only when the remaining depth is zero. The horizontal and height constants also select large-row or raised-row geometry: [confirmed]

$$ \begin{aligned} x_b &= 11+7[r=0], \\ y_b &= b_a + [d=1], \\ x_a &= w_b+17+7[r=0], \\ y_a &= 0, \end{aligned} $$

where $d$ is the one-based structural depth stored at +0x11, $r$ is the render depth, and each bracketed comparison contributes one when true and zero otherwise. The metric pass keeps the large-row base offset only at render depth zero: [confirmed]

$$ \begin{aligned} H &= \max(h_a, b_a+[r=0]+h_b), \\ B &= b_a, \\ W &= w_b+w_a+23+7[r=0]. \end{aligned} $$

The type-0x28 word at +5 is an active-child selector, not a depth or metric field. 34:490034:491D initializes a new structural record to 1. 34:41BB34:41D7 compares the selector with the type’s child count and increments it before entering the next child. Native-source construction follows the 2,1 child order in its eqdisp_child_scan_table row and leaves this field at 1. Interactive template entry can leave the same completed two-child record at 2. Neither value changes the type-0x28 LCD handler. [confirmed]

Reset-origin traces for logbase(12,345), logbase(X,X^2), logbase(3,1//2), and logbase(1//2,3) match every constructed record field. Their complete accepted-write streams contain 99, 79, 91, and 71 writes. These cases cover multi-token children, a powered argument, and a stacked fraction in each child position. [confirmed]

Reset-origin traces for abs(logbase(A,3)), abs(exp(2))-abs(logbase(A,3)), and abs(abs(logbase(A,3))) cover structural depths two and three plus mixed baselines in one leaf. The middle case stores 2 at the second absolute-value record’s +0x0F. The nested log-base records place their base leaf at y=3 while retaining height 9; interactive template entry leaves their active-child selector at 2. After separating that editor state from native-source construction, the stable graph fields and their 79-, 130-, and 95-write LCD streams match the traces. [confirmed]

Eight additional reset-origin traces cover radicals, sequences inside radicals, nested radicals, powers inside radicals, and radicals inside powers. The deepest cases are sqrt(2^X^2), sqrt(sqrt(2)), X^sqrt(2), and sqrt(X^sqrt(2)). Their generated graphs and complete accepted-write streams match the traces. The root bitmap comparison includes accepted writes whose value does not change the LCD byte. [confirmed]

Nth roots and fractions

The type-0x24 constructor maps source token 00F1h through eqdisp_source_type_table, then allocates the containing leaf, structural record, index child, and radicand child. The index uses the raised small-font metrics. The radicand begins four pixels after the index width and four pixels below the parent origin. Its height, width, and baseline determine the structural record metrics. At 34:62D0, an outer nth root selects all seven root-hook rows and a raised nth root selects the final five. [confirmed]

Fresh traces for nthroot(2,2), nthroot(12,X+12), nthroot(3,X^2), and X^nthroot(3,2) match every generated record field and accepted LCD data write. These cases cover a multi-token index, a structural radicand, and a raised nth root. [confirmed]

The type-0x20 constructor maps the stacked-fraction source token EF2Eh through eqdisp_source_type_table. It renders both children one depth below the containing leaf. For numerator height $h_n$, denominator height $h_d$, and child widths $w_n$ and $w_d$, the settled metrics are [confirmed]

$$ \begin{aligned} w &= \max(w_n,w_d), \\ x_n &= 2 + \left\lfloor\frac{w-w_n}{2}\right\rfloor, \\ x_d &= 2 + \left\lfloor\frac{w-w_d}{2}\right\rfloor. \end{aligned} $$

The vertical positions and parent metrics are:

$$ \begin{aligned} y_d &= h_n + 3, \\ H &= h_n + h_d + 3, \\ W &= w + 4, \\ B &= h_n + 1. \end{aligned} $$

The numerator begins at $y=0$. The metric pass clears the numerator leaf’s word at +0x0F. The renderer consumes its payload through the word at +0x11. [confirmed]

eqdisp_allocate_record allocates structural records in a fraction numerator before it allocates the enclosing type-0x20 record. It allocates the numerator leaf afterward. For (X^2)//3, IDs 0x11 and 0x12 identify the power record and its exponent leaf. ID 0x13 identifies the fraction, 0x14 its numerator leaf, and 0x15 its denominator leaf. The graph points from the numerator leaf back to the earlier power record. A structural denominator follows the ordinary recursive allocation order. A fraction nested in the numerator recursively applies the same hoisting rule. [confirmed]

Thirteen reset-origin traces cover leaf, sequence, power, radical, nth-root, and nested-fraction operands. The generated graphs match every captured record field and ID. Their accepted LCD data-write streams also match through the outer eqdisp_render_leaf_program return. [confirmed]

Integral, summation, and nDeriv( records in a fraction numerator follow the same hoisting rule. eqdisp_allocate_record allocates the multi-argument record and reserves its child leaves before it allocates the enclosing type-0x20 fraction. The nested structural record stores 0x10 at +0x13. Raised integral layout uses a 10-pixel body-to-variable gap; the outer layout uses 12 pixels. In a raised nDeriv(X^2,X,...) numerator, the body leaf stores 0x58 before the type-0x2A marker, and the power record stores 4 at +0x0D. [confirmed]

Six reset-origin traces cover integral, summation, and nDeriv( numerators, each with an ordinary body and a powered body. Before parity is accepted, the trace analyzer must decode each settled graph to the asserted expression. The JavaScript constructor then matches every record field and allocation ID, plus every accepted LCD data write through the outer eqdisp_render_leaf_program return. [confirmed]

Integrals, summations, and derivatives

The type-0x22 constructor maps integral source token 0024h through eqdisp_source_type_table. eqdisp_allocate_record allocates the integral record, then reserves all four child leaf IDs before it scans any child payload. The children hold the lower bound, upper bound, body, and differential variable in that order. A structural child allocates its records after all four reservations. A nested integral repeats the same reservation rule recursively. [confirmed]

The bounds render one depth below the containing leaf. The body and variable render at the containing depth. For lower-bound metrics $(h_l,w_l)$, upper-bound metrics $(h_u,w_u)$, body metrics $(h_b,w_b,b_b)$, and variable metrics $(w_v,b_v)$, the integral positions and parent metrics are [confirmed]

$$ \begin{aligned} y_b &= \max(5,h_u), \\ s_l &= \max(5,h_l), \\ H &= y_b+h_b+s_l, \\ B &= y_b+b_b. \end{aligned} $$

The horizontal positions and width are:

$$ \begin{aligned} x_b &= \max(w_l,w_u)+12, \\ x_v &= x_b+w_b+12, \\ W &= x_v+w_v+2, \\ y_v &= B-b_v. \end{aligned} $$

The lower bound begins at $(6,H-h_l)$, the upper bound at $(6,0)$, and the body at $(x_b,y_b)$. The type-0x22 record stores $H$, $W$, and $B$ in the words at +7, +9, and +0x0B. The variable child uses render type 1. [confirmed]

Twelve reset-origin traces cover unequal token-bound widths, a multi-token body, a different variable, power, radical, fraction, and nth-root bodies, structural bounds, and a nested integral. The JavaScript constructor matches every record field and ID. It also reproduces all accepted LCD data writes through the outer 34:660A return. The traces supply comparison oracles, not constructor input. [confirmed]

The type-0x29 constructor maps summation source token EF33h through eqdisp_source_type_table. eqdisp_allocate_record allocates the summation record, then reserves child leaves for the variable, lower bound, upper bound, and body in that order. It fills their payloads after all four reservations. Structural arguments therefore allocate their records after the reserved leaves. A nested summation applies the same rule recursively. [confirmed]

The variable, lower bound, and upper bound render one depth below the containing leaf. The body renders at the containing depth. The variable leaf uses render type 1. For child height, width, and baseline metrics $(h,w,b)$, define [confirmed]

$$ \begin{aligned} L &= w_v+4+w_l, \\ O &= \max(w_u,L,12), \\ S_u &= \max(5,h_u), \\ S_l &= \max(h_v,h_l). \end{aligned} $$

Let $B_0=S_u+4$. The parent and body metrics are:

$$ \begin{aligned} B &= \max(B_0,b_b), \\ y_u &= B-B_0, \\ y_l &= B+5, \\ y_b &= B-b_b, \\ H &= \max(y_l+S_l,y_b+h_b), \\ x_b &= O+6, \\ W &= x_b+w_b+5. \end{aligned} $$

The variable begins at $(0,y_l)$ and the lower bound begins at $(w_v+4,y_l)$. Placing both on the common lower row keeps structural lower bounds aligned with the variable. The upper bound begins at $(\lfloor(O-w_u)/2\rfloor,y_u)$. The body begins at $(x_b,y_b)$. The type-0x29 record stores 3, $H$, $W$, and $B$ at +5, +7, +9, and +0x0B, respectively. [confirmed]

For ordinary five-row limits and a body whose baseline does not exceed $B_0$, these equations reduce to $H=S_u+9+S_l$ and $B=S_u+4$. A reset-origin record capture for sum(A,1,1,sqrt(int(1,3,N,A))//sqrt(A)^1^X) exercises the taller-body branch. The body stores $(h_b,b_b)=(33,18)$; the summation stores $(H,B)=(33,18)$, places the upper limit at $y=9$, and places the lower row at $y=23$. [confirmed]

Eleven reset-origin traces cover the representative sum(N,1,3,N^2) case, unequal-width token limits, multi-token limits, power limits, radical, nth-root, fraction, and power bodies, a different variable, and a nested summation. The JavaScript constructor matches every record field and ID. It also reproduces every accepted LCD data write through the outer 34:660A return. The traces supply comparison oracles, not constructor input. [confirmed]

The settled lower-bound leaf for sum(N,1,3,N^2) contains 0x31. The byte pair EF 1E instead emits display code 0xF7, the empty template square. It appears in captures whose template navigation leaves a slot unfilled, including discarded summation and nDeriv( captures. [confirmed]

The type-0x23 constructor maps source token 0025h through eqdisp_source_type_table. eqdisp_allocate_record allocates the nDeriv( record, then reserves child leaves for the variable, body, and evaluation value in that order. It fills those leaves before it allocates structural descendants of the body or value. A nested nDeriv( applies the same reservation rule recursively. [confirmed]

For body metrics $(h_b,w_b,b_b)$, variable metrics $(h_v,w_v)$, and evaluation-value metrics $(h_e,w_e,b_e)$, the metric branches at 34:7485 and the positioning branches at 34:76C234:76EF produce [confirmed]

$$ \begin{aligned} B &= \max(6,b_b,b_e-4), \\ x_v &= 5, \\ y_v &= B+2, \\ x_b &= 16, \\ y_b &= B-b_b, \\ x_e &= w_b+w_v+29, \\ y_e &= B+4-b_e. \end{aligned} $$

The record height is the union of all three positioned children, and the total width ends after the evaluation value:

$$ \begin{aligned} H &= \max(y_v+h_v,y_b+h_b,y_e+h_e), \\ W &= x_e+w_e. \end{aligned} $$

The type-0x23 record stores 3, $H$, $W$, and $B$ at +5, +7, +9, and +0x0B. The variable leaf uses render type 1. The valid settled scalar case nDeriv(X,X,1) stores 0x58 in both the variable and body leaves. The same body token precedes the type-0x2A marker in valid powered-body captures. [confirmed]

Twelve reset-origin traces cover ordinary and unequal-width arguments, power, radical, fraction, nth-root, and integral bodies, plus nested nDeriv(. The JavaScript constructor matches every record field and ID. It also reproduces every accepted LCD data write through the outer 34:660A return. The traces supply comparison oracles, not constructor input. [confirmed]

A further reset-origin trace covers a tall logBASE( body and a summation evaluation value whose body contains a raised logBASE(. It proves the small-row type-0x28 constants and the $B+4-b_e$ evaluation-value placement. The translated graph matches all 18 records and the final normalized 88-by-19-pixel entry bitmap. The synchronous renderer contributes 195 accepted LCD writes. Their byte-column and row sequence matches the trace after removing an eight-write timer interrupt. [confirmed]

34:6C6B adds the four-pixel glyph advance to logical pen positions 87, 91, and 95. 34:6C76 derives the one-past-right coordinate 96.

Final clipping and the run indicator

The compare at 34:6C7C draws the first two glyphs because their endpoints are 91 and 95; it skips the third glyph because its endpoint is 99. The JavaScript applies the same whole-glyph gate. [confirmed]

The interrupt reaches run_indicator_tick at ram:027B with indicCounter=1 and indicBusy=0x78. 01:6BBA reloads the counter to 0x14, rotates the busy byte to 0x3C, and rewrites pixel 95 across rows 0–7 as 0,0,1,1,1,1,0,0. Inserting this translated operation after the captured 28th renderer operation reproduces all 203 accepted writes, including subsequent read-modify-write bytes, with SHA-256 1cd0a761fab7b948a1bd55cf47d627cdcab0c24620a2da0d3fe8204d1c3691a1. The insertion point is timer phase, not expression-tree state. Generated expression timelines therefore keep this operation labeled as asynchronous UI state. [confirmed]

Flat absolute-value bodies and expressions composed from ordinary token runs, the native Ans, sin(, cos(, tan(, ln(, and log( tokens, right-associated powers, $e^x$, $10^x$, logBASE(, radicals, nth roots, stacked fractions, and numeric matrices now run from tokens through record construction, layout, drawing operations, and LCD byte writes. Integrals, summations, and nDeriv( compose with the same translated forms in their arguments and in a stacked-fraction numerator. The remaining arbitrary-expression branches are still untranslated. [confirmed]

Each dispatch also captures eqdispViewport.logical_x and eqdispViewport.logical_y. Nested fraction 1/2 reaches 34:5DA6 with the local rule (1,6)(5,6) and origin (16,5). Page 4 therefore receives the translated endpoints (17,52) and (21,52). [confirmed]

Record header recap

The fixed 20-byte record header contains a two-byte ID at +0, a type byte at +2, eight unaligned little-endian words at +3, +5, +7, +9, +0x0B, +0x0D, +0x0F, and +0x11, and a byte at +0x13. The analyzer names words by offset until each render type establishes its meaning. Words following the root header are child IDs. 34:6CCD passes an ID through 34:4B05 and 34:4A83 to resolve the child record; these words are not RAM pointers. [confirmed]

Exact point counts matter here. The resolver’s --funcs mode groups an instruction under the nearest preceding symbol. It places 69 instructions in the 39:5167 bucket for each scenario even though the entry itself has zero hits. tools/tests/trace/test_hardware_trace.py covers this distinction. [confirmed]

Page 39 cell encoding

eqdisp_emit_glyph (39:4E8E) interprets each packed D:E cell as one of four output classes:

Cell classMeaningResult
D = 1FhCursor markerUpdate cursor state without drawing a glyph.
D = 82hIndexed string or titleEmit the selected string.
Counted-token case39:6B66 to _KeyToString (45CAh, implemented at 01:6D10)Emit each display code from the counted string.
Direct-glyph caseMapper at 39:4F1AMap the packed cell to one large-font code.

The direct mapper recognizes three ranges: FC3CFC40 becomes E - 3Ch + 5, FE7DFE81 becomes E - 7Dh, and cells with E = 42h and D < 0Ah become glyph D. 00C8 therefore draws the literal name fnInt(, not one glyph. The full decode is in tools/notes/cell-glyph-spec.md and tools/notes/token-name-spec.md; the placement geometry (683D, 6B1C, 5167/5949, pen conversion) is in tools/notes/geometry-spec.md. [confirmed]

The JavaScript translation of 39:4F1A preserves the returned accumulator, carry flag, and every conditional outcome through 39:4F43. The handler-cell classifier consumes that translation rather than a separate mapping table. A pinned-byte interpreter compares all 65,536 D:E inputs. They reduce to nine complete paths and 16 branch outcomes. [confirmed]