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

ISA Reference — Template & 30-Batch Partition

This is the meta page of Part 3 (the per-instruction ISA reference). It owns three things the thirty batch pages B01–B30 all depend on and never re-derive:

  1. The canonical per-instruction page template — the exact schema every B-page follows, specified precisely enough to follow mechanically (§3).
  2. The 30-batch partition — the op-family → batch map over the 1534 shipped mnemonics, grounded in the opcodes[] roster, the opcodes[].package census, and the Opcode_<mn>_Slot_<slot>_encode naming (§4).
  3. The per-mnemonic extraction methodology a reimplementer runs to fill one roster row — read the encode-thunk immediate, map the mnemonic to its module__xdref_* value leaf, cross-check against xtensa-elf-objdump + the libisa decode tables — with a live, ctypes-driven micro-example (§5).

It closes with the roll-up coverage model (§6): how the 30 batch tallies must sum back to the certified 1534 ↔ 12569 (shipped) / 1607 ↔ 12642 (pre-fold) denominators without ever cross-pairing them, and where the 469 / 1065 scalar/vector split and the 1072-op xt_ivp32 package fit.

This page does not emit a per-instruction roster of all 1534 mnemonics — that is the body of B01–B30. It emits the partition, the template, and the methodology. Every count, address, immediate, and symbol below is read or executed against the shipped binaries.

Confidence tags follow the Confidence & Walls Model: OBSERVED = a byte/immediate/symbol read from the shipped binary, or a value computed by executing the shipped simulator; INFERRED = reasoned over OBSERVED facts; CARRIED = re-used at a cited report's confidence; crossed with HIGH/MED/LOW. The page default is [HIGH/OBSERVED]; claims that depart from it carry an explicit tag. Callouts: QUIRK (counter-intuitive but real), GOTCHA (a reimplementation trap), CORRECTION (overturns a naive reading), NOTE (orienting context).

NOTE — the two binaries and their address arithmetic. The encoding side is libisa-core.so (ncore2gp/config/, sha256 8fe68bf462ce76ee17dfbe2167ff8443d473a66385ed115364e9677bf143e451, 9,690,712 B, ET_DYN x86-64, not stripped, no DWARF). The value side is libfiss-base.so (sha256 260b110c…, 12,330,016 B). In libisa-core.so, .text (0x312c10) and .rodata (0x3b6e40) are VMA == file-offset; .data.rel.ro (VMA 0x67bb00 ↔ file 0x47bb00) and .data (VMA 0x764040 ↔ file 0x564040) carry a per-binary delta of 0x200000 (readelf -SW). The count accessors (num_* getters) live in .text and need no delta; the tables they index (opcodes @ 0x6ce6c0, opcodedefs @ 0x6e9640, …) live in .data.rel.ro, file = VMA − 0x200000. Both libraries are in extracted/ (gitignored; reach with an absolute path or fd --no-ignore). Do not carry over the 0x400000 .data delta from libtpu.so — that is a different binary; here it is 0x200000.


1. What Part 3 is, and where this page sits

Part 2 certified that the Vision-Q7 (Cairo / ncore2gp) encoding is a perfect cover; Part 3 enumerates what each instruction is. The denominator is fixed by the coverage tally: 1534 shipped mnemonics, 12569 placements, 864 value leaves. The object model the reference walks is the canonical decode model: ISA → format → slot → opcode → iclass → operand → field, plus the encode matrix opcodedefs[]. The byte-level decode of a bundle is the FLIX bundle-decoding methodology (Part 0); the FLIX grid is the FLIX encoding page; the registers are the eight register files.

Part 3 takes those foundations and produces one roster row per shipped mnemonic, organized into 30 batches. This page is the contract those 30 pages sign: a fixed template so the reference reads uniformly, a fixed partition so no mnemonic is dropped or double-counted, and a fixed extraction recipe so every row is binary-grounded the same way.

NOTE — the partition axis is the libisa mnemonic, not the firmware opcode. There are two distinct instruction rosters in this corpus and Part 3 partitions the larger one. (a) The libisa host-ISA roster — the 1534 Vision-Q7 Xtensa+TIE mnemonics in libisa-core.so (add, ivp_addnx16, wur.fsr, …): the full FLIX-issuable instruction set the disassembler/ISS consume. (b) The firmware kernel-lane opcode roster — the ~140 real NEURON_ISA_TPB_OPCODE values (TENSOR_TENSOR_ARITH_OP = 0x41, POOL = 0x45, …) the GPSIMD device firmware decodes via the 178-entry SEQ dispatch and the kernel_info_table. These are different axes: the 140 firmware opcodes are a coarse compute-instruction enum; the 1534 mnemonics are the fine machine ISA that implements the kernels. B01–B30 partition the 1534, with B30 reconciling the firmware-opcode view (Appendix-P pseudo/fence + the kernel-lane completeness ledger). Never sum a 140-axis count into a 1534-axis tally.


2. The five denominators every batch inherits

The numbers a batch closes against, each read from the binary — a getter immediate and an nm symbol-family count where both exist:

#NumberCountsBinary witnessTag
11534shipped mnemonicsnum_opcodes() @ 0x3b61d0 = mov $0x5fe (=1534); nm | rg -o 'Opcode_(.+)_Slot_…_encode' | sort -u | wc -l = 1534[HIGH/OBSERVED]
212569shipped placements (mnemonic × slot)num_encode_fns() @ 0x3b6130 = mov $0x3119 (=12569); nm | rg -c 'Opcode_.*_Slot_.*_encode' = 12569[HIGH/OBSERVED]
31607 / 12642pre-fold authoring mnemonics / placements (TIE-DB)1534 + 73, 12569 + 73; the +73 fold forms confirmed absent from the roster[HIGH/CARRIED] on 1607/12642, [HIGH/OBSERVED] on +73
4864execution-validated value leavesnm libfiss-base.so | rg -c 'module__xdref_' = 864[HIGH/OBSERVED]
5469 / 1065scalar / vector mnemonic split (name prefix)rg -v '^ivp_' = 469, rg '^ivp_' = 1065, sum 1534[HIGH/OBSERVED]

Secondary dimensions a batch quotes: num_iclasses = 0x5a7 = 1447, num_operands = 0xe8 = 232, num_fields = 0xca5 = 3237, num_formats = 0xe = 14, num_slots = num_decode_fns = 0x2e = 46, num_regfiles = 8, num_regfile_views = 4.

GOTCHA — never cross-pair, and never count from the decompile. The only valid pairings are 1534 ↔ 12569 (shipped) and 1607 ↔ 12642 (pre-fold). Pairing 1534 ↔ 12642 or 1607 ↔ 12569 manufactures a ±73 phantom. And every count must be grounded in either a num_* getter immediate or an nm | rg -c symbol-family population — never a grep of the IDA/Hex-Rays decompile, which inflates 2–12× (one thunk is referenced from many call sites). A batch page that states a count names its witness.


3. The canonical per-instruction page template (the B01–B30 schema)

Every batch page B01–B30 is the same document with a different roster. The schema, in order:

3.1 Required structure

  1. H1 + scope (1 paragraph). # ISA Batch NN — <Family Name>. The scope paragraph names: the op-family the batch owns; the dominant FLIX format(s) and slot(s) those ops occupy; the operand regfile(s); and the batch's place in the 30-batch partition (a one-line back-reference to §4 here).

  2. The batch roster table (the spine — one row per mnemonic the batch owns). Columns, fixed order:

    columncontentsource
    mnemonicthe opcodes[].name stringopcodes[] row
    FLIX format(s)·slot(s)the slot set the mnemonic is placed in (e.g. F0·S3_ALU, F1·S3_ALU, N0·S3_ALU)opcodedefs[] rows for this opcode
    opcode-sel immthe encode-template word0 for a representative slot (the movl $imm operand)the Opcode_<mn>_Slot_<slot>_encode thunk
    operand regfiles + field bitseach operand's regfile (AR/vec/vbool/valign/wvec/b32_pr/gvr/—) + its bit-window in that sloticlasses[]operands[]fields[]
    bundle byte-sizethe byte length of the format(s): one of {2,3,8,16}formats[].length
    semanticsone line — what the op computes (dtype/lane-shape aware)the module__xdref_* leaf body
    [conf]per-row confidence tag (HIGH/MED/LOW × OBSERVED/INFERRED/CARRIED)
  3. Per-mnemonic / per-sub-family deep dives. For each non-trivial op (or each sub-family that shares an iclass), a block with:

    • Encoding bitfield layout — the selector bits in word0, the operand field windows, and (for wide slots) the word1 = 0x00000000 invariant. State the representative slot's template and the per-format selector drift if the family spreads.
    • Annotated C pseudocode naming the real symbol it ports — the module__xdref_<leaf> value body (preferred) or the Opcode_<mn>_Slot_<slot>_encode thunk template. Pseudocode is the disassembled body, not invented; it cites the leaf address.
    • dtype / lane behavior — element width, lane count (nx16 = 32×16b over a 512b vec, 2nx8 = 64×8b, 2x32 = 16×32b, etc.), saturation/wrap, signed/unsigned, rounding mode.
    • QUIRK / GOTCHA / NOTE callouts — counter-intuitive encodings, reimplementation traps, NaN/edge behaviour, fold/alias relationships.
  4. Per-batch coverage tally (the batch's contribution to the roll-up). Three numbers, each with a binary witness: the batch's mnemonic count m; its placement count p (Σ over its mnemonics of opcodedefs[] rows); and its value-leaf count v (the module__xdref_* leaves its mnemonics resolve to). A one-line statement of how m rolls into the 1534 and p into the 12569 (§6).

  5. Cross-links — to this page, to the coverage tally, to the relevant Part-2 deep pages (decode model, FLIX encoding, register files, fp sub-ISA), and to the adjacent batches.

3.2 The roster-row record format (the OBSERVED ground truth a row distills)

Each roster row distills the per-mnemonic record read from the binary. The canonical record shape (one mnemonic, with its full placement list) is:

<mnemonic>  [opc#<row> iclass#<row>=<iclass-name> pkg=<package> flags=<hex> scalar|VECTOR] placements=<k>
    <mnemonic> : <format> : <Slot_name>       : <word0>[/<word1>] : <unit>   : iclass#<row>
    …                                                                          (one line per placement)

This is exactly the schema produced from opcodes[] + opcodedefs[] + the encode thunks. A batch page's roster table is the compression of these records: the FLIX format(s)·slot(s) column lists the placement slots, the opcode-sel imm column gives the representative word0, the bundle byte-size is the format length. The deep dive expands one record in full where the encoding is non-obvious.

NOTE — the encode template is word0; the upper lane is always cleared. Every placement's encoder is the movl-template thunk C7 07 <imm32> [ C7 47 04 <imm32> ] C3*(u32*)(rdi+0) = TEMPLATE, optionally *(u32*)(rdi+4) = WORD1, ret. WORD1 == 0x00000000 with zero exceptions across all 12569 thunks (the upper lane carries no opcode-selector bits — it is merely cleared). A batch quotes only word0; if it shows a wide-slot template it states the /0x00000000 explicitly. Operand fields are deposited separately by field_set/operand_encode, not by this thunk. Worked: Opcode_mov_n_Slot_f0_s3_alu_encode @ 0x3386b0 = movl $0x6498d800,(%rdi); movl $0x0,0x4(%rdi); ret.

GOTCHA — a slot's decoded operand width is NOT next_offset − offset. The _<bitoff>_ token in a slot/field symbol marks where the slot's low byte starts; the rest of the field scatters across high bits. A batch reads the operand bit-window from the Field_<field>_Slot_<slot>_get thunk body (the and/shr/shl chain), never by subtracting adjacent offsets.


4. The 30-batch partition of the 1534 mnemonics

The partition is op-family over the 1534-mnemonic roster. It is anchored to three OBSERVED structures, in priority order:

  1. The name prefixivp_* (1065 vector) vs non-ivp_ (469 scalar). This is the top cut: B01–B24 own the vector ISA, B25–B30 own the base-Xtensa scalar/system ISA. (rg '^ivp_' = 1065, rg -v '^ivp_' = 469.)
  2. The opcodes[].package — the 28-package census, parsed directly from the binary (read opcodes[i].package at table offset +0x08 for all 1534 rows). It sums to exactly 1534 and pins the base-Xtensa region: xt_ivp32 = 1072, xt_ivpn_scalarfp = 102, base-Xtensa (all other 26 packages) = 360.
  3. The verb/suffix sub-family within xt_ivp32 — the functional split (ALU-int / ALU-fp / MAC / load / store / reduce / shift / pack / convert / transcendental / FMA / gather-scatter / select-shuffle / divide / composite) the batch boundaries follow, read from the mnemonic root verb (add, mul, lvn, svn, cvt, recip, …), the dtype suffix (nx16/2nx8/2x32/f16/f32), and the dominant FLIX slot (Mul vs ALU vs LdSt vs Ld). [HIGH/OBSERVED] on the root/suffix reads; [MED/INFERRED] on the exact family boundary where two verbs blur (e.g. plain ivp_mul* straddles ALU and MAC).

4.1 The partition table — B01 → B30

The family column is the batch's owned op-family; axis is the roster axis (ivp_ vector / base scalar / pseudo); package anchor is the opcodes[].package region it draws from; ≈ mnemonics is the partition target the batch will pin exactly (see the CORRECTION below). task is the batch-page task id.

Batchfilefamilyaxispackage anchor≈ mnemonicstask
B01b01-vec-alu-int.mdVector ALU — int add/sub/min/max/cmp/logic coreivp_xt_ivp32 (int ALU)~115#616
B02b02-vec-alu-fp.mdVector ALU — fp16/fp32 add/sub/min/max/cmpivp_xt_ivp32 (fp ALU)~45#617
B03b03-vec-alu-rest.mdVector ALU — B-variant / flag / predicated / abs-diffivp_xt_ivp32~70#618
B04b04-mac-integer.mdInteger MAC matrix — signed mul*/mula*ivp_xt_ivp32 (Mul slot)~110#619
B05b05-mac-mixed.mdMAC — mixed-sign / complex / wide-acc muls*/mulus*ivp_xt_ivp32 (Mul slot)~95#620
B06b06-loads.mdVector loads (lvn*/lsn*/lsrn*) + valign primingivp_xt_ivp32 (Ld/LdSt)~90#621
B07b07-stores.mdVector stores (svn*/ssn*/sbn*)ivp_xt_ivp32 (LdSt)~90#622
B08b08-reduce.mdCross-lane reduce (radd*/rmax*/rmin*/rb*)ivp_xt_ivp32 (ALU)~56#623
B09b09-vec-mov.mdVector move / regfile bridge (mov*/cp*)ivp_xt_ivp32~27#624
B10b10-wvec-pack.mdwvec pack — wide→narrow readout (pack*)ivp_xt_ivp32 (wvec)~42#625
B11b11-vbool-alu.mdvbool ALU / predicate (b* boolean ops)ivp_xt_ivp32+xt_booleans~40#626
B12b12-shift.mdVector shift / rotate / normalize (sll*/srl*/sra*/nsa*)ivp_xt_ivp32 (ALU)~39#627
B13b13-sp-cvt.mdfp32 convert (cvt*…32)ivp_xt_ivp32~30#628
B14b14-hp-lookup.mdfp16 transcendental seeds (recip0.h/rsqrt0.h/exp)ivp_xt_ivp32 (LUT)~18#629
B15b15-sp-lookup.mdfp32 transcendental seeds (recip0/rsqrt0/nexp…32)ivp_xt_ivp32 (LUT)~18#630
B16b16-vec-rep.mdVector replicate / extract / inject (rep*/splat*/inj*)ivp_xt_ivp32~30#631
B17b17-spfma.mdfp32 fused multiply-add (fma…32/madd…32)ivp_xt_ivp32 (Mul)~14#632
B18b18-hp-fma.mdfp16 fused multiply-add (fma…16/madd…16)ivp_xt_ivp32 (Mul)~14#633
B19b19-scatter-gather.mdSuperGather scatter / gather (scatter*/gather*)ivp_xt_ivp32 (gvr/b32_pr)~24#634
B20b20-hp-cvt.mdfp16 convert (cvt*…16)ivp_xt_ivp32~30#635
B21b21-select-shuffle.mdSelect / shuffle / compress (sel*/shfl*/dsel*)ivp_xt_ivp32~33#636
B22b22-unpack-wvec-mov.mdUnpack / wvec move (unpack*/wv* spill)ivp_xt_ivp32 (wvec)~24#637
B23b23-divide.mdVector integer divide (divn*/div* step macros)ivp_xt_ivp32+xt_integerdivide~22#638
B24b24-composite.mdHistogram / squeeze / QLI + scalar-FP FCR/FSRmixedxt_ivpn_scalarfp(102)+7 outliers+xt_ivp32 resid~120#639
B25b25-xt-core.mdbase-Xtensa scalar arith / logic / shiftbasext_core (arith)~105#640
B26b26-xt-ctrl.mdbase-Xtensa ld/st / branch / density / MUL32 / divbasext_core+xt_density+xt_mul+xt_integerdivide~100#641
B27b27-xt-system.mdbase-Xtensa system / SR / reg-window / syncbasext_core(SR)+xt_regwin+xt_sync+xt_externalregisters~75#642
B28b28-xt-exc.mdbase-Xtensa exc-dispatch / bool / loop / minmaxbasext_exception_dispatch(37)+xt_booleans+xt_wide_loop~50#643
B29b29-xt-system2.mdbase-Xtensa debug / timer / cache / MMU / atomicbasext_debug(33)+xt_timer+xt_mmu+xt_instcache+…~75#644
B30b30-appendix-p.mdAppendix-P pseudo / fence + kernel-lane reconciliation + final coveragepseudoxt_virtualops(10)+xt_wide_branch(24) base + the +73 fold~35#645

CORRECTION — the ≈ mnemonics are partition targets, not pre-counted truth; the batch pins the exact count. The exact membership of each batch is determined by the precise slice classifier the batch author runs over the roster (the first-match-wins verb/suffix/package rule of §4.2). The figures here are derived from a deterministic first-pass classification of the 1534-row roster plus the package census, and are accurate to the family but soft at the boundary where two verbs blur (plain ivp_mul* between B04/B05; abs-diff between B01/B03; move between B09/B11). Each B-page is responsible for stating its OBSERVED m (from nm/roster) and proving the partition closes (§6). The hard, non-negotiable anchors the targets must respect: the vector axis totals 1065, the scalar axis 469, and the base-Xtensa packages 360. [HIGH/OBSERVED] on the three hard anchors; [MED/INFERRED] on the per-batch split.

4.2 How each batch's membership is derived (the classifier)

A batch author reproduces the partition mechanically:

for each mnemonic m in roster (1534, C-locale sorted):
    if m starts "ivp_":                       # vector axis (1065)
        n = m without "ivp_"
        # priority order — first match wins:
        if "scatter" in n or "gather" in n:        -> B19
        elif n matches load-verb (lvn|lsn|lsrn|la|lvnx|…):   -> B06
        elif n matches store-verb (svn|ssn|sbn|sv|ss|…):     -> B07
        elif n matches (mula|mac|qmul):                       -> B04   # signed int MAC
        elif n matches (muls|mulus|mulsgn|mulq):              -> B05   # mixed/complex/wide MAC
        elif n matches (fma|madd|msub):     -> B18 if fp16 else B17
        elif n matches (recip|rsqrt|sqrt|nexp|exp): -> B14 if fp16 else B15
        elif n matches div:                                   -> B23
        elif n matches (cvt|round|trunc|float|fix): -> B20 if fp16 else B13
        elif n starts "pack":                                 -> B10
        elif n matches (radd|rmax|rmin|rb|rsum):              -> B08
        elif n matches (sll|srl|sra|nsa|rot|norm|sh):         -> B12
        elif n matches (sqz|qli|hist):                        -> B24
        elif n matches (rep|splat|bcast|inj):                 -> B16
        elif n matches (sel|shfl|dsel|extr|compr|zip):        -> B21
        elif n matches (move|mov|cp):                         -> B09
        elif n matches (unpack|wv|spill):                     -> B22
        elif n matches boolean (b<letter>):                   -> B11
        elif fp-typed (f16/f32/xf):  -> B02 (fp ALU)
        else:                        -> B01 (int ALU) / B03 (residual variant)
    else:                                     # base scalar axis (469)
        classify by opcodes[].package:
            xt_ivpn_scalarfp (102) + 7 xt_ivp32 outliers  -> B24  (scalar-FP)
            xt_core arith/logic/shift                      -> B25
            xt_core ld/st/branch + xt_density + xt_mul + xt_integerdivide -> B26
            xt_core SR + xt_regwin + xt_sync + xt_externalregisters       -> B27
            xt_exception_dispatch + xt_booleans + xt_wide_loop           -> B28
            xt_debug + xt_timer + xt_mmu + xt_instcache + xt_instram/dataram/prefetch/coprocessors/trace/interrupt -> B29
            xt_virtualops + xt_wide_branch (the pseudo/fold base forms)   -> B30

The vector batches (B01–B23) carve xt_ivp32 by verb; B24 collects the xt_ivpn_scalarfp scalar-FP region (the abs.h/add.s/mulsone.h/recipqli.s family — 102 + the 7 xt_ivp32 non-ivp_ outliers {rur/wur.fcr, rur/wur.fsr, recipqli.s, mulsone.s, mulsone.h}) together with the ivp_ composites (sqz/qli/hist). B25–B29 carve the 360 base-Xtensa mnemonics by package; B30 owns the xt_virtualops + xt_wide_branch base forms and reconciles the firmware-opcode view. [HIGH/OBSERVED] on the package carve; [MED/INFERRED] on the xt_ivp32 verb carve boundaries.

GOTCHA — the scalar-FP .h/.s ops are package xt_ivpn_scalarfp, not xt_ivp32, and are scalar by name. All 102 xt_ivpn_scalarfp ops are non-ivp_-prefixed (abs.h, add.s, recip0.h, …) — they count toward the 469 scalar total, not the 1065 vector total, even though they are floating-point. Conversely, 7 ops are package xt_ivp32 but lack the ivp_ prefix (rur.fcr, wur.fcr, rur.fsr, wur.fsr, recipqli.s, mulsone.s, mulsone.h) — so package == xt_ivp32 (1072) is not the same predicate as name starts ivp_ (1065): they differ by exactly these 7. B24 owns both groups (scalar-FP), which is why its target is large.

QUIRK — B30 reconciles the firmware-opcode axis but adds no 1534-axis mnemonics beyond its base forms. Appendix-P pseudo-ops (NEURON_ISA_TPB_OPCODE_PSEUDO_*, 0xC1–0xDF, 31 of them) are compiler-generated and NRT-translated to HW — they have no opcodes[] row, no encode thunk, no value leaf in libisa-core.so, so they are not in the 1534. B30 documents them as a firmware reconciliation (the kernel-lane ledger: 172 union firmware-opcode values → 140 real HW after removing 31 pseudo + 1 INVALID), and its 1534-axis membership is only the shipped xt_virtualops (10) + xt_wide_branch (24) base forms whose .W18/virtual variants fold (§6). The SortMerge op is a phantom — named only in a dead // "SortMerge wip 0x97" comment, with no opcodes[] row (rg -ci sortmerge over the roster = 0); B30 records it as a fabrication wall, never a row.


5. The per-mnemonic extraction methodology

To fill one roster row, a reimplementer runs five binary reads, three of them cross-checks. The recipe is identical for every mnemonic; only the symbol names change.

5.1 The five steps

  1. Find the placements. Scan opcodedefs[] (@0x6e9640, stride 24, file 0x4e9640) for rows whose opcode name (offset +0x00) equals the mnemonic; collect each row's slot name (+0x08) and encode_fn pointer (+0x10). Equivalently, nm libisa-core.so | rg "Opcode_<mangled>_Slot_.*_encode" (mangling: '.'→'_', slot token lowercased — wur.fsrOpcode_wur_fsr_Slot_inst_encode). The count of rows is the mnemonic's placement count k.
  2. Read the opcode-selector template. For each placement's encode_fn (.text, VMA==file), read the thunk bytes C7 07 <imm32> [ C7 47 04 <imm32> ] C3: word0 = the movl operand = the opcode-selector for (mnemonic, slot); word1 = 0x00000000 (invariant). The roster row's opcode-sel imm is a representative word0.
  3. Resolve the operand model. opcodes[].iclass (offset +0x10) → iclasses[] row → its operands[] sub-array → each operands[].field → the Field_<field>_Slot_<slot>_get thunk body = the operand's bit-window in that slot, and operands[].regfile = its file (AR/vec/vbool/valign/wvec/ b32_pr/gvr, or "" for an immediate). OperandSem_<x>_decode gives the value transform (sign-extend/scale/bias/PC-rebase).
  4. Map mnemonic → value leaf. Find the module__xdref_<leaf> symbol in libfiss-base.so whose root matches the mnemonic and whose _<outbits>_<inbits…> suffix matches the dtype. The leaf is the per-element value function; its disassembled body is the row's semantics.
  5. Cross-check three ways. (a) Decode inverse: confirm the slot's Slot_<slot>_decode classifier (decodes[], 46 of them) maps word0 back to the mnemonic. (b) Device objdump: assemble/disassemble the bundle with xtensa-elf-objdump/xtensa-elf-as under XTENSA_SYSTEM=…/XtensaTools/config XTENSA_CORE=ncore2gp and confirm byte/mnemonic agreement. (c) Value execution: call the module__xdref_* leaf via ctypes on an input sweep and diff against an independent model — a bit-exact match is an OBSERVED-by-execution certificate.

NOTE — instruction_mapping.json cross-checks the firmware axis, not the libisa mnemonic. The per-gen instruction_mapping.json (in the customop-lib headers) is a struct ↔ NEURON_ISA_TPB_OPCODE map (e.g. NEURON_ISA_TPB_CTRL_BR_STRUCT → NEURON_ISA_TPB_OPCODE_COMPARE_BRANCH) over the ~140 firmware opcodes — it is the right cross-check for the B30 kernel-lane reconciliation and for any firmware-facing semantics, but it does not index the 1534 libisa mnemonics. For a B01–B24 vector row, the value cross-check is the module__xdref_* leaf; for a firmware-opcode mapping, it is instruction_mapping.json. Keep the two axes separate.

5.2 Worked micro-example — abs (8-bit), driven live through libfiss-base

Take the absolute-value op at 8-bit element width. Step 4 finds the value leaf module__xdref_abs_8_8 (@0x5c0b60 in libfiss-base.so). Its disassembled body:

00000000005c0b60 <module__xdref_abs_8_8>:
  5c0b60: 40 f6 c6 80     test  $0x80,%sil          ; if (in & 0x80)         — sign bit set?
  5c0b64: 74 06           je    5c0b6c              ;   skip
  5c0b66: f7 de           neg   %esi                ;   in = -in
  5c0b68: 40 0f b6 f6     movzbl %sil,%esi          ;   in &= 0xff           — re-narrow to 8b
  5c0b6c: 89 32           mov   %esi,(%rdx)         ; *out = in
  5c0b6e: c3              ret

The ABI is void leaf(int lane /*ignored here*/, int in, int *out)%esi = input, *%rdx = output (3-input ops add a %edx and shift the out-pointer to %rcx, as module__xdref_add_8_8_8 @0x5bc380 shows: add %esi,%edx ; and $0xff,%edx ; mov %edx,(%rcx)). The leaf is license-free, callable in-process — so it can be proven by execution, not merely decoded. Driven live via ctypes:

import ctypes
lib = ctypes.CDLL("libfiss-base.so")
f = lib.module__xdref_abs_8_8
f.restype = None
f.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int)]
def abs8(x):
    out = ctypes.c_int(0)
    f(0, x & 0xFF, ctypes.byref(out))   # arg0=lane(ignored), arg1=in, arg2=*out
    return out.value

Sweep (OBSERVED-by-execution): abs8(0x01)=0x01, abs8(0x7f)=0x7f, abs8(0x80)=0x80, abs8(0x81)=0x7f, abs8(0xff)=0x01, abs8(0xc0)=0x40. This is signed-8 magnitude with the 0x80 → 0x80 two's-complement edge (−128 has no positive 8-bit form, so it returns itself — a real GPSIMD edge a reimplementer must replicate). A full 256-input differential against the disassembled model (((-x)&0xff) if (x&0x80) else x) returned 0 mismatches; the companion module__xdref_add_8_8_8 over the full 65,536-pair space matched (a+b)&0xff with 0 mismatches. Both are OBSERVED-by-execution certificates — the value column of two roster rows, proven not inferred. [HIGH/OBSERVED by execution]

QUIRK — the _<outbits>_<inbits> suffix is the dtype contract, and the first argument is the lane/context slot. abs_8_8 is out8(in8); abs_16_16/abs_32_32 are the 16/32-bit siblings; abs_16f_16f/abs_32f_32f are the fp16/fp32 forms (different bodies — the fp32 form is the branchless shr$0x1f ; neg ; xor ; add idiom @0x5c0b70). A batch row reads the leaf whose suffix matches the placement's dtype, not a single "abs". The leading integer argument is a lane/context selector the simple element leaves ignore but the lane-dependent leaves consume — pass 0 for the scalar element-function check.


6. The roll-up coverage model

The 30 batches partition the 1534, and their tallies must close back onto the certified denominators without cross-pairing. The model a reimplementer audits the reference against:

6.1 The two axes sum independently

   B01 … B23  (vector verb families)   ┐
   B24 (vector composite + scalar-FP)  ├─ vector axis = 1065 (ivp_)
   B25 … B29  (base-Xtensa by package) ┘   scalar axis =  469  (= 109 scalar-FP + 360 base-Xtensa)
   B30 (pseudo/fold base forms)        ───────────────────────────────────────────────────────────
                                                              TOTAL = 1534 shipped mnemonics

The exact bookkeeping, by hard anchor:

  • Vector axis = 1065. B01–B23 plus the ivp_ composites in B24 partition the 1065 ivp_-prefix mnemonics. (Equivalently, xt_ivp32 = 1072 minus the 7 non-ivp_ outliers that B24 takes as scalar-FP.)
  • Scalar-FP = 109 (B24's scalar half) = 102 xt_ivpn_scalarfp + 7 xt_ivp32 non-ivp_ outliers.
  • Base-Xtensa = 360 (the 26 non-vector, non-scalar-FP packages) = B25 ∪ B26 ∪ B27 ∪ B28 ∪ B29 ∪ (B30's xt_virtualops 10 + xt_wide_branch 24 = 34). Each B-page pins its package slice exactly; the sum is the OBSERVED 360.
  • Scalar axis = 469 = 109 scalar-FP (B24) + 360 base-Xtensa (B25–B30). 109 + 360 = 469. ✓
  • Grand total = 1065 (vector) + 469 (scalar) = 1534. ✓

6.2 The placement roll-up pairs ↔ 12569, never 12642

Each batch also tallies placements p_i = Σ (over its mnemonics) of opcodedefs[] rows. The 30 placement tallies sum to 12569 (num_encode_fns = 0x3119), the shipped total. The pre-fold 12642 is the TIE-DB authoring superset (12569 + 73); a batch that touches a fold-source package (xt_wide_branch, xt_virtualops — both in B30) notes the +73 authoring forms do not ship and so do not enter its p. The valid pairings stay 1534 ↔ 12569 (the batches' running total) and 1607 ↔ 12642 (the authoring superset); the reference never carries 1534 ↔ 12642.

6.3 The value-leaf roll-up

Each batch's value-leaf tally v_i (the module__xdref_* leaves its mnemonics resolve to) rolls into the 864 value-leaf denominator. Value leaves are fewer than mnemonics (one leaf serves a whole dtype-family of mnemonics, e.g. abs_8_8 underlies every 8-bit abs placement), so Σ v_i ≤ 864; the base-Xtensa batches (B25–B30) contribute few or no value leaves (their semantics are the architecturally standard Xtensa core, validated by the objdump round-trip, not by xdref execution). The reference's value-coverage claim is 864/864 enumerated, ~95% execution-validated, 0 value bugs across ~2.09M comparisons — inherited from the coverage tally §5.

6.4 The completeness invariant each batch proves

A batch page is complete when: (a) every mnemonic in its partition slice has a roster row; (b) Σ placements over its rows equals its nm-counted placement total; (c) every value-bearing row names a resolved module__xdref_* leaf or is flagged as a base-ISA op with no leaf; and (d) the running Σ m across B01..B30 reaches 1534 and Σ p reaches 12569 with zero slack. B30 carries the final audit line. [HIGH/INFERRED] (the invariant is a derived contract over the OBSERVED denominators).


7. Adversarial self-verification — the five strongest claims

  1. 1534 = 469 scalar + 1065 vector, 12569 placements. num_opcodes() @ 0x3b61d0 = mov $0x5fe (1534); num_encode_fns() @ 0x3b6130 = mov $0x3119 (12569); nm | rg -c 'Opcode_.*_Slot_.*_encode' = 12569; nm | rg -o 'Opcode_(.+)_Slot_…_encode' | sort -u | wc -l = 1534; rg '^ivp_' = 1065, rg -v '^ivp_' = 469 over the roster. Five witnesses agree. Confirmed. [HIGH/OBSERVED]
  2. The 28-package census sums to 1534; xt_ivp32 = 1072, xt_ivpn_scalarfp = 102, base-Xtensa = 360, 7 outliers. Parsed opcodes[i].package (+0x08) for all 1534 rows directly from the binary: xt_ivp32 = 1072, xt_ivpn_scalarfp = 102, sum-of-all = 1534, 28 distinct packages, base-Xtensa (all but the two vector packages) = 360; the 7 xt_ivp32 non-ivp_ outliers are exactly {mulsone.h, mulsone.s, recipqli.s, rur.fcr, rur.fsr, wur.fcr, wur.fsr}. Confirmed. [HIGH/OBSERVED]
  3. The encode-thunk ABI is C7 07 imm32 [C7 47 04 imm32] C3 with word1 == 0. Disassembled: Opcode_wur_fsr_Slot_inst_encode @ 0x341110 = movl $0xf3e900,(%rdi); ret (= WUR | FSR<<8, UR=0xe9); the 2-lane Opcode_mov_n_Slot_f0_s3_alu_encode @ 0x3386b0 = movl $0x6498d800,(%rdi); movl $0x0,0x4(%rdi); retword1 = 0. Confirmed. [HIGH/OBSERVED]
  4. The value leaf is proven by execution, bit-exact. module__xdref_abs_8_8 driven live via ctypes over all 256 inputs matched its disassembled model with 0 mismatches, including the 0x80 → 0x80 two's-complement edge; module__xdref_add_8_8_8 matched (a+b)&0xff over all 65,536 pairs with 0 mismatches. nm libfiss-base.so | rg -c 'module__xdref_' = 864. Confirmed. [HIGH/OBSERVED by execution]
  5. The .data.rel.ro delta is 0x200000, not 0x400000. Per readelf -SW: .text VMA == file 0x312c10; .rodata VMA == file 0x3b6e40; .data.rel.ro VMA 0x67bb00 ↔ file 0x47bb00; .data VMA 0x764040 ↔ file 0x564040 — delta 0x200000. The 0x400000 figure belongs to libtpu.so, a different binary. Confirmed. [HIGH/OBSERVED]

What is not grounded to OBSERVED at the row level. The per-batch ≈ mnemonics in §4.1 are partition targets derived from a first-pass verb/suffix/package classifier plus the package census — [MED/INFERRED] at the family boundary, not exact nm-counted memberships. The three hard anchors (vector 1065, scalar 469, base-Xtensa 360) and the package census are [HIGH/OBSERVED]; the exact split of xt_ivp32's 1072 ops across B01–B24 is the batch authors' job to pin from nm. No claim here asserts a precise per-batch count as OBSERVED.


8. Function & symbol map

All in libisa-core.so unless noted. .text/.rodata: VMA == file. .data.rel.ro/.data: file = VMA − 0x200000.

Symbol / tableAddr (VMA)Role
num_opcodes0x3b61d0mov $0x5fe → 1534 mnemonics
num_encode_fns0x3b6130mov $0x3119 → 12569 placements
num_regfiles / num_regfile_views0x3b5c20 / 0x3b5d508 / 4
num_iclasses/num_operands/num_fields0x3b5fb0/0x3b5e80/0x3b5b401447 / 232 / 3237
num_formats/num_slots/num_decode_fns0x3b65e0/0x3b6510/0x3b64c014 / 46 / 46
opcodes0x6ce6c0 (.data.rel.ro)1534 × {name,package,iclass,flags,…}, stride 72
opcodedefs0x6e9640 (.data.rel.ro)12569 × {opcode,slot,encode_fn}, stride 24
Opcode_wur_fsr_Slot_inst_encode0x341110template 0x00f3e900 (WUR|FSR<<8)
Opcode_mov_n_Slot_f0_s3_alu_encode0x3386b02-lane thunk, word1 = 0
module__xdref_abs_8_80x5c0b60 (libfiss-base.so)signed-8 magnitude value leaf (§5.2)
module__xdref_add_8_8_80x5bc380 (libfiss-base.so)mod-256 add value leaf
xtensa-elf-objdumptools/XtensaTools/bin/device round-trip oracle (XTENSA_CORE=ncore2gp)

9. Cross-references