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

The ISA Datamodel Reflection Layer

All symbols, docstrings, and module offsets on this page apply to neuronx_cc 2.24.5133.0+58f8de22 (cp310 wheel). The Cython .so modules are per-ABI — cp311/cp312 are byte-parallel rebuilds, so any module offset (e.g. PyInit_neuron_isa_tpb_pybind @0xb82f0) is named for cp310 only; re-confirm against the target wheel. Every class name, method name, attribute name, docstring, and default-literal below is read directly from the shipped wheel: the Cython meta-schema modules under neuronxcc/include/isa/datamodels/ (build-id of instruction_info 2acbdc4a…), the pybind11 bridge neuronxcc/isa_tpb/sunda/neuron_isa_tpb_pybind.cpython-310-…so (build-id 0b81969a…), and the C++ generated images in neuronxcc/starfish/lib/libBIR.so (build-id a9b1ea38…). Cython compilation preserves Python identifiers and docstrings as interned .rodata constants (__pyx_n_s_*, __pyx_k_*), which is the recovery surface — these are binary-derived, not invented. See Build & Version Provenance.

Abstract

The struct-family capstone (2.9) typed the Tonga L3 wire format as one compilable .h: a 64-byte bundle whose body is an opcode-discriminated union of ADDR4/TENSOR*/MEM_PATTERN* descriptors. That header answers what the bytes are. This page answers the complementary question: where does the compiler keep the machine-readable description of every instruction, and how does that single description drive both the Python and the C++ encoder so they cannot disagree?

The answer is a four-layer Cython meta-schema shipped under neuronxcc/include/isa/datamodels/ — a self-described "lightweight alternative to pydantic, tailored for ISA instruction datamodels." It is the reflection layer: a small framework (fieldsspecificationsschemadatamodel) that lets every opcode be declared as a typed, self-validating @datamodel class. The authoritative per-opcode declaration is ISAInstructionInfo (in instruction_info.so), whose arch_isa 5-tuple (api_name, arch_isa_name, arch_isa_opcode, arch_isa_type, arch_isa_struct) is the bridge table from the public NKI op name to the silicon. The Python-accessible runtime exposes a deliberately thin pybind11 surface — NeuronInstruction.get_bytes/set_bytes over the raw 64-byte bundle plus a single all-opcodes validator. And the central proof: the same spec is read by one generator (instabrew/brewer.py) that emits two outputs — a Cython front-end op class and a C++ bir::Inst* class — whose JSON wire-key sets are byte-identical, so penguin-emitted IR round-trips losslessly into the C++ BIR.

NOTE (provenance honesty). The generator neuronxcc/instabrew/brewer.py is not shipped in the wheel — only its outputs are (the Cython *OpGen.so carry a verbatim "Generated by brewer … brewer.py at line 3384" provenance line, and the C++ libs carry instabrew/brewer.py as an assert() __FILE__). The generator's contract is therefore reconstructed from its two uniform outputs. Every such reconstruction is tagged INFERRED/STRONG; everything read from a shipped .so is CONFIRMED.

At a glance — the four meta-schema layers

The package is neuronxcc.include.isa.datamodels. Four Cython modules, each a layer; __init__.so re-exports them. Listed bottom-up (each layer consumes the one above it):

LayerModule (cp310 .so)SizeRoleKey surfaceConf
1. fieldsfields.cpython-310…so223 KBtyped-dataclass field primitiveField(), FieldSpec, MISSING; knobs default/default_factory/min_length/pattern/metadataCONFIRMED
2. specificationsspecifications.cpython-310…so71 KBnamed reusable FieldSpec presetsnon_empty, no_space_non_empty (regex ^[^\s]+$), max_count, factor, MAJOR_MINOR, compactCONFIRMED
3. schemaschema.cpython-310…so876 KBruntime type/value validatorsBaseSchema + Int/Float/Bool/Str/None/Any/List/Dict/Optional/Union/Enum/Datamodel Schema, each .validate(value)CONFIRMED
4. datamodeldatamodel.cpython-310…so1.05 MBthe @datamodel framework@datamodel, field_validator, post_init_validator, model_construct/model_copy/model_dump, SchemaValidatorCONFIRMED

The four layers are the meta-schemahow an ISA datamodel is declared and validated. The per-opcode instances live elsewhere: the schema's ISAInstructionInfo/ISAInstructionParam classes are declared in instruction_info.so (§3), and materialized once per opcode in the <op>_info.so modules (e.g. activate2_info.so).

                  ┌──────────────────────────── META-SCHEMA (this page §2) ──────────────────────────┐
  fields.so  ───▶ specifications.so ───▶ schema.so ───▶ datamodel.so (@datamodel framework)
  Field/FieldSpec  no_space_non_empty…   *Schema.validate  ISAInstructionInfo / ISAInstructionParam
                  └─────────────────────────────────────────────┬──────────────────────────────────┘
                                                                 │ declared in
                                                                 ▼
                  instruction_info.so  ── arch_isa 5-tuple ──▶  <op>_info.so   (one ISAInstructionInfo per opcode)
                  (§3 schema classes)                            (§3 instances; e.g. activate2_info)
                                                                 │ read by (unshipped) brewer.py
                                          ┌──────────────────────┴──────────────────────┐
                                          ▼                                              ▼
                  Cython  <Op>Gen.so / <Op>.so  (penguin IR)        C++  bir::Inst<Op>  (libBIR.so)
                  toJson / fromJson  (birpy InstActivation)         toJson / readFieldsFromJson
                                          └────────── same 11/13 wire keys (§5 proof) ──┘
                                                                 │ exposed to Python via
                                                                 ▼
                  neuron_isa_tpb_pybind.so  ── NeuronInstruction.get_bytes/set_bytes(64 B) + is_valid (§4)

1. The four meta-schema layers

Layer 1 — fields.so: the typed-field primitive [CONFIRMED]

fields.so (PyInit_fields, source neuronxcc/include/isa/datamodels/fields.py) is the substrate. Its module docstring, read verbatim from .rodata, is "Field specifications for ISA instruction datamodels." It exports exactly two public names plus a sentinel:

  • Field(...) — a factory returning a dataclass field. Its docstring (verbatim): "A dataclass field with embedded validation specifications in metadata." The recovered worked example in the docstring is the clearest statement of the contract:
    name:   str       = Field(min_length=1, pattern=r'^[A-Za-z]+$')
    emails: List[str] = Field(default_factory=list, min_length=1)
    
  • FieldSpec — the validation-constraint container; docstring "Field specification for validation constraints." (FieldSpec.__init__ is interned).
  • MISSING — the required-field sentinel (docstring line: "Use MISSING for required fields.").

The constraint vocabulary is recovered from the interned docstring lines and __pyx_n_s_* names: default, default_factory, min_length, pattern, metadata, MISSING, message. The mechanism: Field() embeds a FieldSpec into the dataclass field's metadata dict; downstream validators read it back. This is a generic typed-dataclass field decorator — it carries no bit offsets or widths. [STRONG: the wire layout lives in the capstone .h, not here; fields.so only types the Python-level field.]

Layer 2 — specifications.so: named reusable presets [CONFIRMED]

specifications.so is the smallest module (71 KB), docstring "Common validation specifications for ISA instruction datamodels." It wraps Layer-1 FieldSpec into ready-to-apply named presets so opcode declarations reference a name, not a raw constraint. Recovered interned identifiers: non_empty, no_space_non_empty, max_count, factor, MAJOR_MINOR, compact.

The decisive recovery is the regex behind no_space_non_empty, present verbatim in the .rodata string pool:

^[^\s]+$

GOTCHA. ^[^\s]+$ is the ground-truth lexical rule for ISA mnemonics. Every opcode/field api_name is constrained no_space_non_empty — non-empty and whitespace-free. If you reimplement the op registry, this is the exact validity predicate a mnemonic must satisfy; an empty or space-containing name is rejected at validated_init time, not silently coerced.

The same module's .rodata carries the build banner Copyright (c) 2025, Amazon.com. All Rights Reserved, the build path /opt/workspace/KaenaCompilerNativeBuild-310/build/private/src-3.10.16, and GCC: (GNU) 11.5.0 20240719 (Red Hat 11.5.0-5) — pinning the Cython toolchain.

Layer 3 — schema.so: the runtime validator hierarchy [CONFIRMED]

schema.so (876 KB) is a JSON-Schema-style runtime type system. It imports FieldSpec from Layer 1 and exposes a class hierarchy of *Schema nodes, every node a class with a .validate(value) method. The full roster, recovered from qualified __pyx_* names and docstrings:

BaseSchema      "Base class for all schema types."     (.__init__, .validate, abstractmethod)
IntSchema       "Schema for validating integer values."
FloatSchema     FloatSchema.validate                   (float)
BoolSchema                                              (bool)
StrSchema       "Schema for validating string values." (min_length, pattern)
NoneSchema                                              (None only)
AnySchema       "Schema that accepts any value."        (wildcard / pass-through)
ListSchema(item_schema)                                 (homogeneous list)
DictSchema(key_schema, value_schema, keys_are_strings)
OptionalSchema(inner_schema)                            (allows None)
UnionSchema(union_schemas: list[BaseSchema])
EnumSchema(enum_class)                                  ← the enum-DOMAIN check
DatamodelSchema(model_class)                            ← validates a nested @datamodel

The validation semantics are recovered verbatim from the error-message .rodata — these are how a spec constraint becomes a runtime check inside <Schema>.validate():

Schema nodeError string (verbatim)
IntSchema'<name>' must be an integer, got <type>
FloatSchema'<name>' must be a float, got <type>
BoolSchema'<name>' must be a boolean, got <type>
StrSchema'<name>' must be a string, got <type> / '<name>' does not match required pattern: <pat>
NoneSchema'<name>' must be None, got <type>
ListSchema'<name>' must be a list, got <type>
DictSchema'<name>' must be a dict, got <type>
UnionSchema'<value>' does not match any union types

Two custom exceptions live here: ValidationError ("Raised when field validation fails.") and SchemaError ("Raised when schema definition is invalid."). This layer validates Python-level types and value rangesmin_length/max_count/pattern constraints, sourced from Layer-1/2 FieldSpec, are enforced here. It does not carry bit offsets; those are the C++ INST_UNION bitfields the capstone documents. [STRONG: name-and-type validation only; complementary to the wire layer, not redundant with it.]

Layer 4 — datamodel.so: the @datamodel framework [CONFIRMED]

datamodel.so (1.05 MB) is the declaration framework — the "lightweight pydantic." Its module docstring, read verbatim: "A lightweight alternative to pydantic, tailored for ISA instruction datamodels." The public surface:

  • @datamodel — class decorator; docstring "A decorator that performs runtime type and custom validation to dataclass." It wraps a @dataclass and installs the model API.
  • field_validator / post_init_validator — decorators marking a function as a per-field or post-init validator.
  • The injected model API (all interned): model_construct ("Construct an instance bypassing validation."), model_copy ("Create a deep copy of the model with optional field updates."), model_dump ("Export model as a dictionary."), and validated_init (the validating __init__ replacement).
  • The internal collectors/runners: _collect_field_validators, _collect_post_init_validators, _run_field_validators, _run_post_init_validators, _setup_validation.
  • SchemaValidator + the type-hint→schema builders _build_schema / _build_list_schema / _build_dict_schema / _build_union_schema — these map a Python type hint onto the Layer-3 *Schema nodes. So when a @datamodel class annotates params: List[ISAInstructionParam], _build_list_schema mints a ListSchema(DatamodelSchema(ISAInstructionParam)) and validate() recurses element-wise.

The canonical example embedded verbatim in the @datamodel docstring is the keystone — it names the ISA classes directly:

@datamodel
class ISAInstructionInfo:
    api_name: str
    params: List[ISAInstructionParam]

@datamodel
class ISAInstructionParam:
    ...

This is the meta-schema closing on itself: the framework's own docstring demonstrates it by declaring the very ISA classes that instruction_info.so instantiates.


2. ISAInstructionInfo and the arch_isa 5-tuple [CONFIRMED]

instruction_info.so (1.04 MB, neuronxcc.include.isa.instruction_info) is where the Layer-4 example becomes a real, populated schema. It declares the @datamodel-decorated classes that are the per-opcode field schema.

ISAInstructionInfo — docstring "An ISA Instruction description for public API." Its fields (recovered from interned names) split into a public API name, a bridge to silicon, and a typed operand list:

@datamodel
class ISAInstructionInfo:
    api_name:        str                          # public op/mnemonic (no_space_non_empty)
    arch_isa_name:   str                          # the CamelCase NEURON_ISA_TPB enum member
    arch_isa_opcode: ...                          # the wire opcode byte (low byte of 0x10NN)
    arch_isa_type:   ...                          # the NEURON_ISA_TPB_OPCODE enum constant
    arch_isa_struct: str                          # the C++ INST_UNION arm, e.g. "s2d2_ac_struct"
    default_engine:  NeuronEngine                 # which engine executes it
    params:          List[ISAInstructionParam]    # the ordered operand/field list
    constraints:     ISAInstructionConstraints    # group legality (ConstraintList / …PerChip)
    assertions:      List[ISAAssertion]           # named legality predicates
    performance:     ISAPerformanceEstimation     # the per-op latency model
    traits:          ISAInstructionTraits
    docs:            ISADoc

Its post-init validators — validate_unique_names (every param name unique), validate_same_dtype_params, validate_same_par_size_params, validate_same_free_size_params — are exactly the cross-field group checks that fire through the Layer-4 _run_post_init_validators path.

The arch_isa 5-tuple. Verified present in instruction_info.so (strings … | rg -w): api_name, arch_isa_name, arch_isa_opcode, arch_isa_type, arch_isa_struct, default_engine. This is the complete bridge from the public NKI op to silicon:

Tuple memberBinds toCross-reference
api_namepublic NKI / user-facing mnemonic
arch_isa_nameCamelCase op-enum member (e.g. Activate, Matmul)the neuron_isa.so op roster
arch_isa_opcodethe wire opcode bytethe BIR roster opcode (e.g. Matmul 0x02)
arch_isa_typethe NEURON_ISA_TPB_OPCODE enum constantenum ordinals (2.23, planned)
arch_isa_structthe C++ INST_UNION arm s#d#_<tag>_structthe capstone .h union arm

i.e. instruction_info.so is the bridge table that lets the compiler translate one public op into a wire opcode, an engine, a union arm, and a field list — without that table, the op name and the silicon would be two disconnected namespaces.

ISAInstructionParam — docstring "A parameter description of an ISA Instruction for public API using composition." One operand/field of an opcode. It carries name, a param_info (one of three sub-models below), default_val (or MISSING → required), rd_wr_trait, and predicates is_tensor/is_immediate/is_read/is_write. The three composition sub-models — the field-type taxonomy — are all verified present:

ISATensorParamInfo     "Information specific to tensor parameters."
   → num_partitions_isa_name, free_dim_count_isa_name, dtype_isa_name, par_dim_max, has_known_size
ISAImmediateParamInfo  "Information specific to immediate parameters."   (scalar/vector)
   → imm_type_isa_name
ISAFieldParamInfo      "Information specific to field parameters."       (enum-valued: AluOp, AccumCmd, …)

This is the second tier of the three-name arch mapping: every ISA-visible quantity carries both a public name and an arch/wire ISA name. A tensor param's dtype_isa_name / num_partitions_isa_name / free_dim_count_isa_name, and an immediate's imm_type_isa_name, are the silicon field names that the per-opcode validators key on. Per-chip variation (e.g. an opcode that shifts byte between CoreV2 and CoreV4) is carried by ConstraintListPerChip inside constraintsone ISAInstructionInfo per op spans all generations; the arch layer selects the override at emit time.

The bit-exact widths/offsets are not in this Python schema — it carries typed field names, dtype names, defaults, and constraints. The bit layout is the C++ INST_UNION (capstone), enforced by the pybind validator (§4). The two are complementary layers, not redundant.


3. The pybind11 runtime — NeuronInstruction.get_bytes/set_bytes [CONFIRMED]

The Python-accessible runtime ISA is the pybind11 bridge neuronxcc/isa_tpb/sunda/neuron_isa_tpb_pybind.cpython-310…so (930 KB; PyInit_neuron_isa_tpb_pybind @0xb82f0). This is the genuine compiled-C++ validator — its module docstring (verbatim): "Python bindings for Neuron ISA TPB assertion functions using pybind11." It is not Cython; it is real pybind11 (the .rodata carries pybind11::handle, error_already_set, the build path …/pybind11/*).

The registered surface is deliberately thin — it does not expose per-field bit accessors to Python. The 64-byte bundle is opaque to Python; it is moved as a flat byte array and validated in C++:

// pybind11 module surface (recovered from .rodata symbol/docstring constants):
py::class_<NeuronInstruction> "NeuronInstruction"
    .name        : str                      // the opcode mnemonic
    .instruction : <union payload>
    .get_bytes() -> Sequence[int]           // read the 64-byte wire bundle
    .set_bytes(Sequence[int]) -> None       // write the 64-byte wire bundle

py::class_<DebugResult> "DebugResult"
    .result         : bool
    .error_messages : list[str]             // the names of FAILED per-field asserts

is_valid_neuron_instruction(NeuronInstruction)     -> bool
    // "Check if the instruction is a valid Neuron instruction"
dbg_is_valid_neuron_instruction(NeuronInstruction) -> DebugResult
    // "Debug version: Check if the instruction is a valid Neuron instruction"

All of NeuronInstruction, get_bytes, set_bytes, is_valid_neuron_instruction, dbg_is_valid_neuron_instruction, DebugResult, and error_messages are verified as interned strings in this .so. The underlying C++ type is NEURON_ISA_TPB_INST_UNION — the 25-char Itanium length-prefixed mangling 25NEURON_ISA_TPB_INST_UNION (and the validator signatures bRK25NEURON_ISA_TPB_INST_UNIONE / DebugResultRK25…) are present in .rodata. The opcode-enum prefix NEURON_ISA_TPB_OPCODE_ and the runtime errors Opcode is NEURON_ISA_TPB_OPCODE_… / opcode is not a known Neuron opcode confirm the union is opcode-discriminated. This is the same 64-byte INST_UNION the capstone types.

The "schema query" via 64 bytes. Because no per-field accessor is exposed, the Python way to ask "is this field combination legal?" is: assemble the 64-byte bundle (via the isa_construction_helpers.create_tensorNd_mem_pattern builders), wrap it as NeuronInstruction(name, bytes), and call dbg_is_valid_neuron_instruction() — the returned DebugResult.error_messages lists the names of every violated per-field assertion. The rich per-opcode field/assert vocabulary (the d{2,3,4}_<op>_* field families and the *_check predicates) lives inside the C++ validator body, keyed by the opcode discriminant; only the assertion names survive as strings.

The per-opcode field families and the assertion idiom are verified in the .so string pool: opcode discriminants like s_s3d3_mm_opcode; descriptor-prefixed field names d3_mm_dtype, d3_mm_valid_xbus, d3_mm_valid_src_partition, d3_mm_valid_col_group_active_col, d3_mm_reserved2; the dtype legality checks type_fp32r_illegal / type_uint64_illegal_check; and the failure idiom inst failed assertion check: '<predicate_name>'. The descriptor prefix encodes the union arm: s = source-AP version, d# = dest-descriptor generation — the same s#d#_<tag>_struct naming as arch_isa_struct (§2).

The construction front-end (neuronxcc/isa_tpb/python/isa_construction_helpers.so, Cython) exposes the bundle builders create_tensor1d_mem_pattern … create_tensor4d_mem_pattern, whose descriptor inputs (num_elem, step_elem, psum_partition_address, …) are verified present and match the TENSOR1–4D descriptors one (step, num_elem) pair per dimension. The companion enum_mapping.so carries the dtype bridge map_dtype / map_alu over the Dtype enum — FP32R, BFLOAT16, FP8_EXP3/FP8_EXP4/FP8_EXP5 all verified — the authoritative dtype roster the dtype_isa_name field checks validate against.


4. One spec, two encoders — the single-spec → two-output proof [CONFIRMED]

This is the page's central claim: one ISA datamodel spec drives both the Python and the C++ encoder, and the proof is that their JSON wire-key sets are byte-identical. The mechanism is a single generator, neuronxcc/instabrew/brewer.py, that is a multi-target emitter.

4.1 One generator, present in both back-ends [CONFIRMED]

The decisive artifact is the path string …/neuronxcc/instabrew/brewer.py, verified present (one occurrence each) in all three C++ libraries:

$ strings -n6 libBIR.so          | rg -c instabrew/brewer.py   →  1
$ strings -n6 libwalrus.so       | rg -c instabrew/brewer.py   →  1
$ strings -n6 libBIRSimulator.so | rg -c instabrew/brewer.py   →  1

In the C++, this path is the __FILE__ argument of generated assert() macros — it is loaded into RSI immediately before call __assert_fail@plt (glibc ABI __assert_fail(expr, FILE, line, func)), with the companion func argument naming generated per-op bodies such as bool bir::InstCall::sameInst(bir::Instruction*). So the C++ translation unit containing those bir::Inst* methods was emitted by brewer.py.

The identical generator is the Python provenance, read verbatim from ActivationOpGen.so:

  Generated by brewer from the definition in neuronxcc/instabrew/brewer.py at line 3384

NOTE. brewer.py itself is not in the wheel (it is a build-time tool). Its multi-target emitter behaviour — read one ISAInstructionInfo spec, emit a Python class and a C++ bir::Inst* class — is INFERRED from the two uniform outputs; the brewer.py provenance string in both languages is CONFIRMED.

4.2 The two outputs agree on the wire keys [CONFIRMED]

Take Activation (spec source: activate2_info.so, arch_isa_struct = "s2d2_ac_struct").

C++ sidebir::InstActivation in libBIR.so, verified by nm -DC at the exact addresses from the disassembly:

bir::InstActivation::toJson(…)              @0x435450   // SERIALIZE
bir::InstActivation::readFieldsFromJson(…)  @0x417f00   // DESERIALIZE
bir::InstActivation::createFromJson(…)      @0x425b10   // FACTORY → readFieldsFromJson

toJson emits and readFieldsFromJson reads the same 11 wire keys (symmetric, lossless round-trip):

func, op0, op1, reverse0, reverse1, reduce_op, scale, acc, alpha, is_activate2, can_read_uninit

reverse0, reverse1, reduce_op, is_activate2, can_read_uninit are all verified present in libBIR.so's string pool. These keys are the brewer-emitted serialization of activate2_info's params — func ← activation_func, op0/op1 ← the tensor-scalar AluOps, reverse0/reverse1"reverse operand order for first/second operation" (the verbatim spec docstring), alpha ← relu_param, etc.

Python sidebirpy/InstructionOpcodes.so defines a class named exactly InstActivation with methods InstActivation.toJson, InstActivation.fromJson, and InstActivation.setAcc (all verified interned), carrying the same wire-key vocabulary. .setAcc corresponds to the C++ acc key.

activate2_info  (ONE ISA datamodel spec)
   ├─ brewer.py ─▶ Python  birpy InstActivation.toJson / .fromJson  ── 11 keys
   └─ brewer.py ─▶ C++     bir::InstActivation::toJson / readFieldsFromJson ── 11 keys   (SAME SET)

InstMatmult is the second, independent confirmation: bir::InstMatmultBase::toJson/readFieldsFromJson round-trip 13 keys (accumulation_flag, psum_zero_region, replication_resolution, ifmap_quant_offset, perf_mode, … — all verified in libBIR.so), and the Python birpy InstMatmult carries 13/13 verbatim.

4.3 Enums serialize as strings — so the spellings must agree [CONFIRMED]

The wire encoding of every enum-valued field is the enum NAME string, not an integer. The C++ JSON serializers call <Enum>2string, verified by nm -DC on libBIR.so:

bir::Dtype2string(bir::Dtype)                                      @0x2641e0
bir::string2Dtype(std::string const&)                             @0x265fb0   (inverse)
bir::AluOpType2string(bir::AluOpType)                             @0x400600
bir::ActivationFunctionType2string(bir::ActivationFunctionType)  @0x4002a0

Because the wire carries the name string, the Python emitter must produce the identical spelling for the round-trip to parse — and it does, because both sides project the same spec enum domain. birpy/InstructionOpcodes.so imports neuronxcc.starfish.penguin.dtypes for its Dtype enum; the C++ Dtype is the 20-member enum (ordinals 0..19) whose names the Python BIR layer reuses.

The round-trip safety guarantee. Single-spec generation structurally prevents the classic two-implementation drift bugs: a field added on one side only (both regenerate from one params list), an enum value spelled differently (one <Enum>2string table), a key-name/order skew (same brewer template, same param order), a dtype-tag mismatch (one Dtype enum). The spec is the single source of truth; both languages are projections of it; so a BIR emitted by Python parses losslessly in C++ and re-emits byte-stable. This is why toJson key-set == readFieldsFromJson key-set holds for both Activation (11) and Matmult (13).

4.4 The inheritance contract is identical across languages [STRONG]

Python: Activation(NeuronInst), MatMul : MatMulOpBase : NeuronInst. C++ (verified via RTTI __si_class_type_info relocations): InstActivation : bir::Instruction, InstMatmult : InstMatmultBase : bir::Instruction. The IR-plumbing root NeuronInst maps to bir::Instruction; the generated base owns the spec fields + serialize/verify, and op-specific logic layers on top. The Python two-module split (<Op>OpGen.so + <Op>.so) is a Cython packaging choice; the C++ side folds base + behaviour into one TU (with the Inst<Op>Base/Inst<Op> split where a shared base is needed). The brewer generator (Part 7, 7.3) is the same emitter on both paths.


Reconstructed mechanism — spec → field accessor → 64-byte get/set

Annotated pseudocode naming the real recovered symbols. The framework half (Layers 1–4) is CONFIRMED from the shipped .so; the brewer template is INFERRED from its uniform output (brewer.py not shipped).

# ── LAYER 4: declare one opcode as a @datamodel (CONFIRMED: instruction_info.so) ──
@datamodel                                  # datamodel.so: installs validated_init, model_dump, …
class ISAInstructionInfo:                   # docstring "An ISA Instruction description for public API"
    api_name:        str  = Field(metadata=no_space_non_empty)   # specifications.so preset: ^[^\s]+$
    arch_isa_name:   str                    # the arch_isa 5-tuple (§2) — bridge to silicon
    arch_isa_opcode: int                    #   → wire opcode byte
    arch_isa_type:   ...                    #   → NEURON_ISA_TPB_OPCODE enum constant
    arch_isa_struct: str                    #   → "s2d2_ac_struct" INST_UNION arm
    default_engine:  NeuronEngine
    params:          List[ISAInstructionParam]   # the ordered field list

# ── LAYER 4: validated_init maps each annotation onto a LAYER-3 schema, then validates ──
def _build_schema(type_hint):               # datamodel.so
    if is List[T]:   return ListSchema(_build_schema(T))          # schema.so
    if is Enum:      return EnumSchema(enum_class)                #   enum-DOMAIN check
    if is @datamodel:return DatamodelSchema(model_class)          #   recurse
    if is int:       return IntSchema()      # "'<name>' must be an integer, got <type>"
    ...                                      # Str/Bool/Float/Optional/Union/Dict/None/Any
# field constraints (min_length/pattern) come from the LAYER-1 FieldSpec in field.metadata

# ── (UNSHIPPED) brewer.py reads ISAInstructionInfo, emits TWO encoders [INFERRED template] ──
#   for p in spec.params:
#       emit getter  property  p.name      -> self._<p.name>
#       emit ctor arg p.name (default = p.default_val; required if MISSING)
#       emit serialize:  result[p.arch_isa_name or p.name] = _emit(self._<p.name>)
#                        # _emit: x.serialize() if model/opcode/operand; <Enum>2string if enum;
#                        #        number-wrap if scalar; 'none' if Optional unset
#   ⇒ Python <Op>.toJson  AND  C++ bir::Inst<Op>::toJson  — SAME key set (§4.2 CONFIRMED)
// ── RUNTIME: the 64-byte bundle is opaque to Python; validated in C++ (CONFIRMED) ──
// neuron_isa_tpb_pybind.so — NeuronInstruction wraps NEURON_ISA_TPB_INST_UNION (64 B)
struct NeuronInstruction {                  // py::class_ "NeuronInstruction"
    std::string                 name;       // .name  = opcode mnemonic
    NEURON_ISA_TPB_INST_UNION   instruction;// 64-byte bundle; raw[0] = opcode discriminant
    std::vector<unsigned char>  get_bytes() const;            // read 16 dwords
    void                        set_bytes(std::vector<unsigned char>);  // write 16 dwords
};
bool        is_valid_neuron_instruction(const NeuronInstruction&);      // → bool
DebugResult dbg_is_valid_neuron_instruction(const NeuronInstruction&);  // .error_messages =
//   names of the violated d{2,3,4}_<op>_* asserts, e.g. "type_fp32r_illegal" — keyed by raw[0]

Cross-References

  • NEURON_ISA_TPB Struct-Family Capstone (the .h) (2.9) — the 64-byte INST_UNION bitfield layout this layer reflects; arch_isa_struct names its union arms, and the pybind get_bytes/set_bytes move exactly those 64 bytes.
  • PE Matmul Encoding — Dense / Sparse / MX & Quantize (2.10) — the d3_mm_* / InstMatmultBase field names this layer reflects; the 13-key Matmult wire-key proof of §4.2 is the encoding that page documents.
  • ISA Enum Ordinals (2.23, planned) — the numeric values behind arch_isa_type / the Dtype / AluOpType enum-name strings that §4.3 shows serialize by name.
  • Methodology & the Confidence Model — the CONFIRMED/STRONG/INFERRED grounding tags; the "generator-not-shipped, reconstruct-from-output" pattern used for brewer.py.
  • Build & Version Provenance — the cp310/cp311/cp312 per-ABI .so rebuild note that makes every module offset version-pinned.
  • The brewer generator (Part 7, 7.3) — the multi-target emitter whose two outputs §4 proves agree; this page documents its contract from the wheel side, Part 7 from the BIR side.