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:
- The canonical per-instruction page template — the exact schema every B-page follows, specified precisely enough to follow mechanically (§3).
- The 30-batch partition — the op-family → batch map over the 1534 shipped mnemonics, grounded
in the
opcodes[]roster, theopcodes[].packagecensus, and theOpcode_<mn>_Slot_<slot>_encodenaming (§4). - 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 againstxtensa-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 was re-read or executed against the shipped binaries this pass.
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. 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/, sha2568fe68bf462ce76ee17dfbe2167ff8443d473a66385ed115364e9677bf143e451, 9,690,712 B, ET_DYN x86-64, not stripped, no DWARF). The value side islibfiss-base.so(sha256260b110c…, 12,330,016 B). Inlibisa-core.so,.text(0x312c10) and.rodata(0x3b6e40) are VMA == file-offset;.data.rel.ro(VMA0x67bb00↔ file0x47bb00) and.data(VMA0x764040↔ file0x564040) carry a per-binary delta of0x200000(readelf -SW, re-read this pass). The count accessors (num_*getters) live in.textand need no delta; the tables they index (opcodes@0x6ce6c0,opcodedefs@0x6e9640, …) live in.data.rel.ro, file = VMA −0x200000. Both libraries are inextracted/(gitignored; reach with an absolute path orfd --no-ignore). Do not carry over the0x400000.datadelta fromlibtpu.so— that is a different binary; here it is0x200000.[HIGH/OBSERVED]
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 realNEURON_ISA_TPB_OPCODEvalues (TENSOR_TENSOR_ARITH_OP = 0x41,POOL = 0x45, …) the GPSIMD device firmware decodes via the 178-entry SEQ dispatch and thekernel_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 a140-axis count into a1534-axis tally.[HIGH/OBSERVED]
2. The five denominators every batch inherits (re-grounded this pass)
The numbers a batch closes against, each re-read from the binary this pass — a getter immediate and
an nm symbol-family count where both exist:
| # | Number | Counts | Binary witness (this pass) | Tag |
|---|---|---|---|---|
| 1 | 1534 | shipped mnemonics | num_opcodes() @ 0x3b61d0 = mov $0x5fe (=1534); nm | rg -o 'Opcode_(.+)_Slot_…_encode' | sort -u | wc -l = 1534 | [HIGH/OBSERVED] |
| 2 | 12569 | shipped placements (mnemonic × slot) | num_encode_fns() @ 0x3b6130 = mov $0x3119 (=12569); nm | rg -c 'Opcode_.*_Slot_.*_encode' = 12569 | [HIGH/OBSERVED] |
| 3 | 1607 / 12642 | pre-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 |
| 4 | 864 | execution-validated value leaves | nm libfiss-base.so | rg -c 'module__xdref_' = 864 | [HIGH/OBSERVED] |
| 5 | 469 / 1065 | scalar / vector mnemonic split (name prefix) | rg -v '^ivp_' = 469, rg '^ivp_' = 1065, sum 1534 | [HIGH/OBSERVED] |
Secondary dimensions a batch quotes (same transcript, this pass): 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. [HIGH/OBSERVED]
GOTCHA — never cross-pair, and never count from the decompile. The only valid pairings are
1534 ↔ 12569(shipped) and1607 ↔ 12642(pre-fold). Pairing1534 ↔ 12642or1607 ↔ 12569manufactures a±73phantom. And every count must be grounded in either anum_*getter immediate or annm | rg -csymbol-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.[HIGH/OBSERVED]
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
-
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). -
The batch roster table (the spine — one row per mnemonic the batch owns). Columns, fixed order:
column content source mnemonicthe opcodes[].namestringopcodes[]rowFLIX 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 opcodeopcode-sel immthe encode-template word0for a representative slot (themovl $immoperand)the Opcode_<mn>_Slot_<slot>_encodethunkoperand regfiles + field bitseach operand's regfile (AR/vec/vbool/valign/wvec/b32_pr/gvr/—) + its bit-window in that slot iclasses[]→operands[]→fields[]bundle byte-sizethe byte length of the format(s): one of {2,3,8,16}formats[].lengthsemanticsone 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)— -
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) theword1 = 0x00000000invariant. 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 theOpcode_<mn>_Slot_<slot>_encodethunk 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 512bvec,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.
- Encoding bitfield layout — the selector bits in
-
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 countp(Σover its mnemonics ofopcodedefs[]rows); and its value-leaf countv(themodule__xdref_*leaves its mnemonics resolve to). A one-line statement of howmrolls into the 1534 andpinto the 12569 (§6). -
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 the slice survey reads 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 the gateway roster survey produces 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 thunkC7 07 <imm32> [ C7 47 04 <imm32> ] C3—*(u32*)(rdi+0) = TEMPLATE, optionally*(u32*)(rdi+4) = WORD1,ret.WORD1 == 0x00000000with zero exceptions across all 12569 thunks (the upper lane carries no opcode-selector bits — it is merely cleared). A batch quotes onlyword0; if it shows a wide-slot template it states the/0x00000000explicitly. Operand fields are deposited separately byfield_set/operand_encode, not by this thunk. Re-verified this pass:Opcode_mov_n_Slot_f0_s3_alu_encode@0x3386b0=movl $0x6498d800,(%rdi); movl $0x0,0x4(%rdi); ret.[HIGH/OBSERVED]
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 theField_<field>_Slot_<slot>_getthunk body (theand/shr/shlchain), never by subtracting adjacent offsets.[HIGH/OBSERVED]
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:
- The name prefix —
ivp_*(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, this pass.)[HIGH/OBSERVED] - The
opcodes[].package— the 28-package census, parsed directly from the binary this pass (readopcodes[i].packageat table offset+0x08for 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.[HIGH/OBSERVED] - 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 (MulvsALUvsLdStvsLd).[HIGH/OBSERVED]on the root/suffix reads;[MED/INFERRED]on the exact family boundary where two verbs blur (e.g. plainivp_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.
| Batch | file | family | axis | package anchor | ≈ mnemonics | task |
|---|---|---|---|---|---|---|
| B01 | b01-vec-alu-int.md | Vector ALU — int add/sub/min/max/cmp/logic core | ivp_ | xt_ivp32 (int ALU) | ~115 | #616 |
| B02 | b02-vec-alu-fp.md | Vector ALU — fp16/fp32 add/sub/min/max/cmp | ivp_ | xt_ivp32 (fp ALU) | ~45 | #617 |
| B03 | b03-vec-alu-rest.md | Vector ALU — B-variant / flag / predicated / abs-diff | ivp_ | xt_ivp32 | ~70 | #618 |
| B04 | b04-mac-integer.md | Integer MAC matrix — signed mul*/mula* | ivp_ | xt_ivp32 (Mul slot) | ~110 | #619 |
| B05 | b05-mac-mixed.md | MAC — mixed-sign / complex / wide-acc muls*/mulus* | ivp_ | xt_ivp32 (Mul slot) | ~95 | #620 |
| B06 | b06-loads.md | Vector loads (lvn*/lsn*/lsrn*) + valign priming | ivp_ | xt_ivp32 (Ld/LdSt) | ~90 | #621 |
| B07 | b07-stores.md | Vector stores (svn*/ssn*/sbn*) | ivp_ | xt_ivp32 (LdSt) | ~90 | #622 |
| B08 | b08-reduce.md | Cross-lane reduce (radd*/rmax*/rmin*/rb*) | ivp_ | xt_ivp32 (ALU) | ~56 | #623 |
| B09 | b09-vec-mov.md | Vector move / regfile bridge (mov*/cp*) | ivp_ | xt_ivp32 | ~27 | #624 |
| B10 | b10-wvec-pack.md | wvec pack — wide→narrow readout (pack*) | ivp_ | xt_ivp32 (wvec) | ~42 | #625 |
| B11 | b11-vbool-alu.md | vbool ALU / predicate (b* boolean ops) | ivp_ | xt_ivp32+xt_booleans | ~40 | #626 |
| B12 | b12-shift.md | Vector shift / rotate / normalize (sll*/srl*/sra*/nsa*) | ivp_ | xt_ivp32 (ALU) | ~39 | #627 |
| B13 | b13-sp-cvt.md | fp32 convert (cvt*…32) | ivp_ | xt_ivp32 | ~30 | #628 |
| B14 | b14-hp-lookup.md | fp16 transcendental seeds (recip0.h/rsqrt0.h/exp) | ivp_ | xt_ivp32 (LUT) | ~18 | #629 |
| B15 | b15-sp-lookup.md | fp32 transcendental seeds (recip0/rsqrt0/nexp…32) | ivp_ | xt_ivp32 (LUT) | ~18 | #630 |
| B16 | b16-vec-rep.md | Vector replicate / extract / inject (rep*/splat*/inj*) | ivp_ | xt_ivp32 | ~30 | #631 |
| B17 | b17-spfma.md | fp32 fused multiply-add (fma…32/madd…32) | ivp_ | xt_ivp32 (Mul) | ~14 | #632 |
| B18 | b18-hp-fma.md | fp16 fused multiply-add (fma…16/madd…16) | ivp_ | xt_ivp32 (Mul) | ~14 | #633 |
| B19 | b19-scatter-gather.md | SuperGather scatter / gather (scatter*/gather*) | ivp_ | xt_ivp32 (gvr/b32_pr) | ~24 | #634 |
| B20 | b20-hp-cvt.md | fp16 convert (cvt*…16) | ivp_ | xt_ivp32 | ~30 | #635 |
| B21 | b21-select-shuffle.md | Select / shuffle / compress (sel*/shfl*/dsel*) | ivp_ | xt_ivp32 | ~33 | #636 |
| B22 | b22-unpack-wvec-mov.md | Unpack / wvec move (unpack*/wv* spill) | ivp_ | xt_ivp32 (wvec) | ~24 | #637 |
| B23 | b23-divide.md | Vector integer divide (divn*/div* step macros) | ivp_ | xt_ivp32+xt_integerdivide | ~22 | #638 |
| B24 | b24-composite.md | Histogram / squeeze / QLI + scalar-FP FCR/FSR | mixed | xt_ivpn_scalarfp(102)+7 outliers+xt_ivp32 resid | ~120 | #639 |
| B25 | b25-xt-core.md | base-Xtensa scalar arith / logic / shift | base | xt_core (arith) | ~105 | #640 |
| B26 | b26-xt-ctrl.md | base-Xtensa ld/st / branch / density / MUL32 / div | base | xt_core+xt_density+xt_mul+xt_integerdivide | ~100 | #641 |
| B27 | b27-xt-system.md | base-Xtensa system / SR / reg-window / sync | base | xt_core(SR)+xt_regwin+xt_sync+xt_externalregisters | ~75 | #642 |
| B28 | b28-xt-exc.md | base-Xtensa exc-dispatch / bool / loop / minmax | base | xt_exception_dispatch(37)+xt_booleans+xt_wide_loop | ~50 | #643 |
| B29 | b29-xt-system2.md | base-Xtensa debug / timer / cache / MMU / atomic | base | xt_debug(33)+xt_timer+xt_mmu+xt_instcache+… | ~75 | #644 |
| B30 | b30-appendix-p.md | Appendix-P pseudo / fence + kernel-lane reconciliation + final coverage | pseudo | xt_virtualops(10)+xt_wide_branch(24) base + the +73 fold | ~35 | #645 |
CORRECTION — the
≈ mnemonicsare 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 (run this pass) plus the package census, and are accurate to the family but soft at the boundary where two verbs blur (plainivp_mul*between B04/B05; abs-diff between B01/B03;movebetween B09/B11). Each B-page is responsible for stating its OBSERVEDm(fromnm/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/.sops are packagext_ivpn_scalarfp, notxt_ivp32, and are scalar by name. All 102xt_ivpn_scalarfpops 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 packagext_ivp32but lack theivp_prefix (rur.fcr,wur.fcr,rur.fsr,wur.fsr,recipqli.s,mulsone.s,mulsone.h) — sopackage == xt_ivp32(1072) is not the same predicate asname starts ivp_(1065): they differ by exactly these 7. B24 owns both groups (scalar-FP), which is why its target is large.[HIGH/OBSERVED]
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 noopcodes[]row, no encode thunk, no value leaf inlibisa-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 + 1INVALID), and its 1534-axis membership is only the shippedxt_virtualops(10) +xt_wide_branch(24) base forms whose.W18/virtual variants fold (§6). TheSortMergeop is a phantom — named only in a dead// "SortMerge wip 0x97"comment, with noopcodes[]row (rg -ci sortmergeover the roster = 0); B30 records it as a fabrication wall, never a row.[HIGH/OBSERVED]
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
- Find the placements. Scan
opcodedefs[](@0x6e9640, stride 24, file0x4e9640) for rows whoseopcodename (offset+0x00) equals the mnemonic; collect each row'sslotname (+0x08) andencode_fnpointer (+0x10). Equivalently,nm libisa-core.so | rg "Opcode_<mangled>_Slot_.*_encode"(mangling:'.'→'_', slot token lowercased —wur.fsr→Opcode_wur_fsr_Slot_inst_encode). The count of rows is the mnemonic's placement countk. - Read the opcode-selector template. For each placement's
encode_fn(.text, VMA==file), read the thunk bytesC7 07 <imm32> [ C7 47 04 <imm32> ] C3:word0= themovloperand = the opcode-selector for(mnemonic, slot);word1=0x00000000(invariant). The roster row'sopcode-sel immis a representativeword0. - Resolve the operand model.
opcodes[].iclass(offset+0x10) →iclasses[]row → itsoperands[]sub-array → eachoperands[].field→ theField_<field>_Slot_<slot>_getthunk body = the operand's bit-window in that slot, andoperands[].regfile= its file (AR/vec/vbool/valign/wvec/ b32_pr/gvr, or""for an immediate).OperandSem_<x>_decodegives the value transform (sign-extend/scale/bias/PC-rebase). - Map mnemonic → value leaf. Find the
module__xdref_<leaf>symbol inlibfiss-base.sowhose 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'ssemantics. - Cross-check three ways. (a) Decode inverse: confirm the slot's
Slot_<slot>_decodeclassifier (decodes[], 46 of them) mapsword0back to the mnemonic. (b) Device objdump: assemble/disassemble the bundle withxtensa-elf-objdump/xtensa-elf-asunderXTENSA_SYSTEM=…/XtensaTools/config XTENSA_CORE=ncore2gpand confirm byte/mnemonic agreement. (c) Value execution: call themodule__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.jsoncross-checks the firmware axis, not the libisa mnemonic. The per-geninstruction_mapping.json(in the customop-lib headers) is astruct ↔ NEURON_ISA_TPB_OPCODEmap (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 themodule__xdref_*leaf; for a firmware-opcode mapping, it isinstruction_mapping.json. Keep the two axes separate.[HIGH/OBSERVED]
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, re-read this pass:
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
this pass:
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_8isout8(in8);abs_16_16/abs_32_32are the 16/32-bit siblings;abs_16f_16f/abs_32f_32fare the fp16/fp32 forms (different bodies — the fp32 form is the branchlessshr$0x1f ; neg ; xor ; addidiom @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 — pass0for the scalar element-function check.[HIGH/OBSERVED]
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 1065ivp_-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+ 7xt_ivp32non-ivp_outliers. - Base-Xtensa = 360 (the 26 non-vector, non-scalar-FP packages) = B25 ∪ B26 ∪ B27 ∪ B28 ∪ B29 ∪
(B30's
xt_virtualops10 +xt_wide_branch24 = 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. [HIGH/OBSERVED]
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. [HIGH/OBSERVED]
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, re-checked this pass
1534 = 469 scalar + 1065 vector,12569placements.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]- The 28-package census sums to 1534;
xt_ivp32 = 1072,xt_ivpn_scalarfp = 102, base-Xtensa = 360, 7 outliers. Parsedopcodes[i].package(+0x08) for all 1534 rows directly from the binary this pass:xt_ivp32 = 1072,xt_ivpn_scalarfp = 102, sum-of-all = 1534, 28 distinct packages, base-Xtensa (all but the two vector packages) = 360; the 7xt_ivp32non-ivp_outliers are exactly{mulsone.h, mulsone.s, recipqli.s, rur.fcr, rur.fsr, wur.fcr, wur.fsr}. Confirmed.[HIGH/OBSERVED] - The encode-thunk ABI is
C7 07 imm32 [C7 47 04 imm32] C3withword1 == 0. Re-disassembled this pass:Opcode_wur_fsr_Slot_inst_encode@0x341110=movl $0xf3e900,(%rdi); ret(=WUR | FSR<<8, UR=0xe9); the 2-laneOpcode_mov_n_Slot_f0_s3_alu_encode@0x3386b0=movl $0x6498d800,(%rdi); movl $0x0,0x4(%rdi); ret—word1 = 0. Confirmed.[HIGH/OBSERVED] - The value leaf is proven by execution, bit-exact.
module__xdref_abs_8_8driven live via ctypes over all 256 inputs matched its disassembled model with 0 mismatches, including the0x80 → 0x80two's-complement edge;module__xdref_add_8_8_8matched(a+b)&0xffover all 65,536 pairs with 0 mismatches.nm libfiss-base.so | rg -c 'module__xdref_'= 864. Confirmed.[HIGH/OBSERVED by execution] - The
.data.rel.rodelta is0x200000, not0x400000.readelf -SWthis pass:.textVMA == file0x312c10;.rodataVMA == file0x3b6e40;.data.rel.roVMA0x67bb00↔ file0x47bb00;.dataVMA0x764040↔ file0x564040— delta0x200000. The0x400000figure belongs tolibtpu.so, a different binary. Confirmed.[HIGH/OBSERVED]
What I could not ground 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 / table | Addr (VMA) | Role |
|---|---|---|
num_opcodes | 0x3b61d0 | mov $0x5fe → 1534 mnemonics |
num_encode_fns | 0x3b6130 | mov $0x3119 → 12569 placements |
num_regfiles / num_regfile_views | 0x3b5c20 / 0x3b5d50 | 8 / 4 |
num_iclasses/num_operands/num_fields | 0x3b5fb0/0x3b5e80/0x3b5b40 | 1447 / 232 / 3237 |
num_formats/num_slots/num_decode_fns | 0x3b65e0/0x3b6510/0x3b64c0 | 14 / 46 / 46 |
opcodes | 0x6ce6c0 (.data.rel.ro) | 1534 × {name,package,iclass,flags,…}, stride 72 |
opcodedefs | 0x6e9640 (.data.rel.ro) | 12569 × {opcode,slot,encode_fn}, stride 24 |
Opcode_wur_fsr_Slot_inst_encode | 0x341110 | template 0x00f3e900 (WUR|FSR<<8) |
Opcode_mov_n_Slot_f0_s3_alu_encode | 0x3386b0 | 2-lane thunk, word1 = 0 |
module__xdref_abs_8_8 | 0x5c0b60 (libfiss-base.so) | signed-8 magnitude value leaf (§5.2) |
module__xdref_add_8_8_8 | 0x5bc380 (libfiss-base.so) | mod-256 add value leaf |
xtensa-elf-objdump | tools/XtensaTools/bin/ | device round-trip oracle (XTENSA_CORE=ncore2gp) |
9. Cross-references
- ISA Coverage & the 1534/1607/12642 Tally — the certified
denominators (1534/12569/864), the 28-package census, the
+73fold, the no-cross-pair law. - The Canonical ISA Decode Model (libisa-core) — the
formats → slots → opcodes → iclasses → operands → fieldsobject model +opcodedefs[]encode matrix this template walks. - The libisa Table Schema & Codec ABI — the struct layouts / strides / encode-template ABI the extraction recipe reads.
- The FLIX VLIW Encoding — the 14-format / 46-slot grid and the
per-slot placement census the roster's
format·slotcolumn draws from. - The Eight Register Files — the AR/vec/vbool/valign/wvec/b32_pr/gvr files the roster's operand column names.
- The FP Sub-ISA (FCR/FSR, RNE/RZ) — the scalar-FP rounding state B24's
xt_ivpn_scalarfpfamily plumbs. - FLIX Bundle-Decoding Methodology (Part 0) — the byte-level decode the device-objdump cross-check leg validates against.
- The Confidence & Walls Model — the tags and the named walls
(
F4/F6interiors, FLIX-desync, v5,MODULE_SCHEDULE,SortMergephantom). - Forward — the thirty batch pages B01–B30 (
b01-vec-alu-int.md…b30-appendix-p.md): each follows the §3 template, owns the §4 partition slice, and closes onto the §6 roll-up.