RNG Seed-State Opcodes (0x77 RandGetState / 0x78 RandSetState)
This page documents the two opcodes that save and restore the GPSIMD datapath RNG
state — the per-lane PRNG words that the Xorwow, TIE-Xorwow,
LFSR, and Philox generators advance. 0x77 RAND_GET_STATE
serializes the live generator state out to a destination tensor; 0x78
RAND_SET_STATE deserializes a generator state in from a source tensor (or an
inline immediate). Together they form a clean checkpoint pair: a model can dump the RNG
state to memory at a kernel boundary and reload it later to reproduce or migrate the
draw sequence. These two ops close the datapath-RNG (GpSimd) opcode surface — every
generator the previous pages decoded now has a save/restore path, and the draw/seed/checkpoint
roles are fully accounted for.
These ops are not number generators. They do not draw; they only walk the generator's
state words between an addressable tensor and the per-lane state buffer in DRAM/SBUF
scratch. They are also architecturally distinct from the PE engine's
PeManageSeed (0x08), which manages the PSUM stochastic-rounding seeds —
a different opcode, a different engine, a different struct, a different RNG domain. See §7.
This is the Cadence Vision-Q7 GPSIMD compute core's own firmware — windowed-ABI Xtensa
code on the ncore2gp (Cairo) core — together with the NX/SEQ sequencer front-end that
validates the operand before it reaches the compute core. Every device fact below is
byte-pinned to a carve from libnrtucode_internal.so; every host-ISA
fact is read out of the public aws_neuron_isa_tpb_*.h headers shipped in the same
customop-lib package and gcc-compiled for offset/sizeof ground truth.
Confidence and evidence tags follow the project
Confidence & Walls Model: HIGH/MED/LOW ×
OBSERVED/INFERRED/CARRIED.
NOTE — the objects used. The firmware container is
…/custom_op/c10/lib/libnrtucode_internal.so(10,276,288 B, sha256b7c67e898a116454…— the FW-26/FW-27/FW-28/FW-41 anchor). The host ISA headers live under…/custom_op/c10/include/neuron_{sunda,cayman,mariana,maverick}_arch_isa/tpb/(= NeuronCore v2/v3/v4/v5). The two operand structsS1_RAND(set) andD4_RAND(get) are compiled withgccagainst the mariana, sunda and maverick headers; thesizeof/offsetofvalues below are emitted by that compile. The string-sweep counts arestrings -a … \| rg -F -cover the binary.
1. The headline
- The two opcodes are named verbatim and maintained on all four generations. The
NEURON_ISA_TPB_OPCODEenum givesRAND_GET_STATE = 0x77andRAND_SET_STATE = 0x78, each flagged// Y(maintained) in every gen'saws_neuron_isa_tpb_common.h(sunda L207/208, cayman L210/211, mariana L215/216, maverick L218/219). 0x77is GET (save),0x78is SET (restore) — not swapped. The enum order is explicit (RAND0x76 →RAND_GET_STATE0x77 →RAND_SET_STATE0x78), and the struct binding confirms the polarity: GET takes the destination-tensor struct, SET takes the source-tensor struct (§3).- The operand structs are compile-verified 64 B.
0x78 RAND_SET_STATE → S1_RAND_STRUCT(sizeof==64,src_mem_pattern@16SBUF-only);0x77 RAND_GET_STATE → D4_RAND_STRUCT(sizeof==64,dst_mem_pattern@44SBUF+PSUM, shared with the legacyRAND0x76). Both pindtype == UINT32(0x9).[HIGH/OBSERVED — gcc compile] - The saved state is the per-lane PRNG state buffer in memory, not a hardware register. The firmware logs "Initializing XORWOW state in DRAM scratch"; the ISA register roster has no RNG/seed/xorwow state SR/UR. The Get/Set interface exists precisely because the state is addressable memory.
- The state width is a function of
(engine, generator, algorithm)and is fixed by the host validators'legal_combinationstable: Pool keeps Xorwow=6 / LFSR=1 / Philox=7 u32 words; the wider DVE lanes keep Xorwow=24 / LFSR=4; Act keeps LFSR=2. ThedtypeisUINT32on every arm. - The dispatch is
SEQ → 0xf0 ExtendedInst → per-engine body. The NX/SEQ front-end logsS: RandGetState/S: RandSetState; the0xf0extended-instruction escape registersExtendedInstRandGetState/ExtendedInstRandSetState; the per-engine body forks onrand_algorithminto the sharedSet/GetSeedsbodies (the same fork the draw path uses). - Per-gen handler presence trails the opcode. The opcode is
// Yeverywhere, but the working algo bodies arrive incrementally: SUNDA defines the op but wires only Pool+Philox (itsrand_algoenum has no XORWOW); CAYMAN adds software Xorwow; MARIANA adds LFSR and the multi-engine (Pool/DVE/Act) surface; MAVERICK keeps Pool+DVE but drops the Act arm (§6). - These two close the datapath-RNG opcode surface (§8) and are kept distinct from the PE
stochastic-rounding seed op
0x08 PeManageSeed(§7) and the one-shotSET_RNG_SEEDpseudo0xd0(§7.3).
2. The names + per-gen flag — the 4-gen opcode enum
Source: aws_neuron_isa_tpb_common.h, NEURON_ISA_TPB_OPCODE enum, per-arch dir
neuron_{sunda,cayman,mariana,maverick}_arch_isa/tpb/ (= NC-v2/v3/v4/v5).
| gen | common.h line (get / set) | value | flag |
|---|---|---|---|
| SUNDA (v2) | 207 / 208 | 0x77 / 0x78 | // Y / // Y |
| CAYMAN (v3) | 210 / 211 | 0x77 / 0x78 | // Y / // Y |
| MARIANA (v4) | 215 / 216 | 0x77 / 0x78 | // Y / // Y |
| MAVERICK (v5) | 218 / 219 | 0x77 / 0x78 | // Y / // Y |
So RAND_GET_STATE = 0x77, RAND_SET_STATE = 0x78, both // Y (maintained) in all four
gens. [HIGH/OBSERVED]
Neighbour anchors (mariana common.h): 0x4D RNG // Y (the POOL Xorwow draw handler,
Xorwow); 0x76 RAND // n, ucode exists, not maintained/used (the legacy
general-HW draw, dormant); 0x7f DROPOUT // Y (the inline-RNG consumer, Dropout);
0xe2 RAND2 // Y (the modern DVE draw, Rand2). The seed-state pair 0x77/0x78
stays maintained across the RAND → RAND2 generational handoff — it serves whichever
generator the kernel selects. [HIGH/OBSERVED — common.h L163/187/214/223/302]
GOTCHA — do not read
RAND(0x76,// n) as a synonym for the seed-state ops.0x76is the legacy draw op (dormant);0x77/0x78are the checkpoint ops (maintained). They share theD4_RANDstruct on the GET side (§3) but are different opcodes with different semantics.
3. The operand structs — compile-verified
The authoritative struct↔opcode binding is the shipped
neuron_<gen>_arch_isa/tpb/instruction_mapping.json:
// neuron_mariana_arch_isa/tpb/instruction_mapping.json
"NEURON_ISA_TPB_D3_RAND_STRUCT": [ "NEURON_ISA_TPB_OPCODE_RAND2" ], // L64-65
"NEURON_ISA_TPB_D4_RAND_STRUCT": [ "NEURON_ISA_TPB_OPCODE_RAND", // L76-78
"NEURON_ISA_TPB_OPCODE_RAND_GET_STATE" ],
"NEURON_ISA_TPB_S1_RAND_STRUCT": [ "NEURON_ISA_TPB_OPCODE_RAND_SET_STATE" ], // L205-206
So 0x78 RAND_SET_STATE → S1_RAND, 0x77 RAND_GET_STATE → D4_RAND (shared with 0x76 RAND),
0xe2 RAND2 → D3_RAND. [HIGH/OBSERVED]
3a. 0x78 RAND_SET_STATE → S1_RAND_STRUCT (the SRC / restore variant, 64 B)
Compile-verified offsets (gcc … ; offsetof; ISA_STATIC_ASSERT(sizeof==64)):
| off | field | type / size | role |
|---|---|---|---|
| 0 | header | NEURON_ISA_TPB_HEADER (4) | opcode byte @0 = 0x78 |
| 4 | events | NEURON_ISA_TPB_EVENTS (8) | sync events |
| 12 | rand_algorithm | RAND_ALGORITHM (1) | {LFSR=0,PCG32=1,PHILOX=2,XORWOW=3} |
| 13 | num_active_channels | uint8_t (1) | live-lane bound (≤ POOLING_NUM_CHANNELS) |
| 14 | update_state | RAND_STATE_UPDATE (1) | {SRC_TENSOR=0, IMM_SINGLE=1, IMM_LANE=2} |
| 15 | in_dtype | DTYPE (1) | pinned UINT32 (0x9) |
| 16 | src_mem_pattern | TENSOR1D (8) | the STATE INPUT, SBUF-only |
| 24 | rand_generator | RAND_SRC (1) | {RNG_LFSR=0,RNG_XORWOW=1,RNG_PHILOX=2,OUTPUT_CVT_LFSR=3} |
| 25 | reserved[7] | uint8_t[7] (7) | must be 0 (has_s1_rand_reserved_zero, checks [0..6]) |
| 32 | imm_state[8] | uint32_t[8] (32) | the 8-word inline immediate state |
sizeof(NEURON_ISA_TPB_S1_RAND_STRUCT) == 64 [HIGH/OBSERVED — gcc compile, all gens].
Two state-input modes, encoded in update_state:
update_state == SRC_TENSOR (0): the state is read fromsrc_mem_pattern(an SBUFTENSOR1Dwhosenum_elem[0]must equal the algo's word count —rand_set_state_elem_cnt), and all 8imm_state[]words must be 0 (rand_set_state_imm_zero). This is the normal restore from a checkpoint tensor path.update_state != SRC_TENSOR(IMM_SINGLE/IMM_LANE): the state comes inline fromimm_state[]. The only inline-legal generator is Philox, and even thenimm_state[7] == 0is required (has_valid_rand_set_state_imm,s1_rand.hL162-175).
The src_mem_pattern is validated tensor1d_valid(…, WriteTensor::False, AllowedInPSUM::False, AllowedInSBUF::True) — i.e. a read-only SBUF source (s1_rand.h L128-131).
3b. 0x77 RAND_GET_STATE → D4_RAND_STRUCT (the DST / save variant, 64 B, shared with 0x76 RAND)
Compile-verified offsets (gcc … ; offsetof; ISA_STATIC_ASSERT(sizeof==64)):
| off | field | type / size | role on GET |
|---|---|---|---|
| 0 | header | HEADER (4) | opcode byte @0 = 0x77 |
| 4 | events | EVENTS (8) | sync events |
| 12 | rand_algorithm | RAND_ALGORITHM (1) | which generator's state to dump |
| 13 | rand_num_steps | uint8_t (1) | forced 0 on GET (rand_get_state_unused_field_zero) |
| 14 | post_process | RAND_POST_PROC (1) | forced 0 on GET |
| 15 | rand_generator | RAND_SRC (1) | coupled with rand_algorithm |
| 16 | params[4] | RAND_PARAM (16) | forced 0 on GET |
| 32 | dtype | DTYPE (1) | pinned UINT32 (0x9, rand_get_state_valid_dtype) |
| 33 | reserved1[1] | uint8_t (1) | must be 0 |
| 34 | num_active_channels | uint8_t (1) | live-lane bound |
| 35 | reserved2[9] | uint8_t[9] (9) | must be 0 |
| 44 | dst_mem_pattern | TENSOR4D (20) | the STATE OUTPUT, SBUF+PSUM |
sizeof(NEURON_ISA_TPB_D4_RAND_STRUCT) == 64.
GET reuses the RAND op's 4D struct because it writes the state out to a 4D destination.
The Rand-op-specific fields (rand_num_steps, post_process, params) are all forced to 0 by
rand_get_state_unused_field_zero (d4_rand.h L187-194), so on the GET path the struct
degenerates to (algorithm, generator, dtype=UINT32, num_active_channels, dst_mem_pattern). The
dst_mem_pattern is validated tensor4d_valid(…, WriteTensor::True, AllowedInPSUM::True, AllowedInSBUF::True) — a writable tensor allowed in PSUM or SBUF (d4_rand.h L213-216).
QUIRK — the source/destination asymmetry is the whole design. SET reads from an SBUF-only
TENSOR1Dsource (@16, read-only); GET writes to an SBUF-or-PSUMTENSOR4Ddestination (@44, writable). GET is broader (PSUM allowed) because dumping state to a PSUM bank is cheap; SET is narrower (SBUF-only) because the restore source is a model-supplied tensor. The two are a deliberate checkpoint pair, not symmetric mirror ops.
3c. The element-count contract (the state width is encoded in the tensor shape)
The number of u32 state words is not a struct field — it is the element count of the operand
tensor, checked by rand_set_state_elem_cnt(i, N) (src_mem_pattern.num_elem[0] == N,
s1_rand.h L133-135) and rand_get_state_elem_cnt(i, N)
(t4d_element_count(dst_mem_pattern) == N, d4_rand.h L249-251). N is fixed per
(engine, generator, algorithm) by the legal_combinations validators (§4).
4. The semantics — which state, what width, per engine × algo
The host validators rand_set_state_legal_combinations / rand_get_state_legal_combinations
(mariana s1_rand.h L63-126 / d4_rand.h L218-247, read verbatim) enumerate the exact
u32 word count per (engine, generator, algorithm). GET mirrors SET arm-for-arm, with one
structural difference: SET splits the Philox arm into two (IMM_SINGLE + SRC_TENSOR), GET
has a single Philox arm — so SET has 8 legal arms, GET has 7 on mariana.
| engine | rand_generator | rand_algorithm | state words (u32) | note |
|---|---|---|---|---|
| Pool | RNG_PHILOX (2) | PHILOX (2) | 7 | imm_state[7]==0; SRC or IMM_SINGLE (set has both arms) |
| Pool | RNG_XORWOW (1) | XORWOW (3) | 6 | the 6-word per-lane Xorwow state |
| Pool | OUTPUT_CVT_LFSR (3) | LFSR (0) | 1 | the 1-word LFSR state |
| DVE | RNG_XORWOW (1) | XORWOW (3) | 24 | the wide DVE-lane Xorwow state |
| DVE | RNG_LFSR (0) | LFSR (0) | 4 | DVE LFSR |
| DVE | OUTPUT_CVT_LFSR (3) | LFSR (0) | 4 | DVE output-convert LFSR |
| Act | OUTPUT_CVT_LFSR (3) | LFSR (0) | 2 | mariana-only (dropped on maverick, §6) |
[HIGH/OBSERVED — every arm pins UINT32]
NOTE —
update_state == SRC_TENSORon every restore arm. All eight SET arms except the first Philox arm (IMM_SINGLE) requireupdate_state == SRC_TENSOR. The loneIMM_SINGLEarm is the inline-Philox seed/restore path (s1_rand.hL64-69). Every restore from a checkpoint tensor usesSRC_TENSOR.
4a. Which RNG state (the answer)
- The state save/restored is the per-lane PRNG state buffer held in DRAM/SBUF scratch — not a
hardware state register. The firmware string
Xorwow(SW)/Xorwow(TIE) : Initializing XORWOW state in DRAM scratchis observed in the ucode container; the ISA register roster has zero rng/seed/xorwow state SR/UR. Get/Set read/write the state from/to the operand mem-pattern precisely because the state lives in addressable memory. - Which generator is selected by the coupled
(rand_generator, rand_algorithm)pair, eachlegal_combinationsarm fixing the coupling (RNG_XORWOW↔XORWOW,RNG_LFSR/OUTPUT_CVT_LFSR↔LFSR,RNG_PHILOX↔PHILOX). So0x77/0x78are the generic checkpoint op for whicheverrand_algothe kernel uses.
State formats (cross-anchored to the algo kernels):
- XORWOW — the 6-word per-lane state
(x, y, z, w, v= 5 xorshift words+ d= Weyl counter). The Xorwow SW path recovers the Marsaglia default seed vector byte-exact (x=0x075BCD15, y=0x159A55E5, z=0x1F123BB5, w=0x05491333, v=0x00583F19) with Weyl incrementd += 362437 (0x000587C5). On Pool the checkpoint width is 6; on the wider DVE lanes it is 24 (the DVE Xorwow keeps a 4×-wider per-lane state).[HIGH width; CARRIED seed/Weyl] - LFSR — one u32 word per lane.
d4_rand.hstates it verbatim: "LFSR treats each of the 128 lanes as an independent random number generator. The lowest u32 word of the rand_state (rand_state[0]) for each lane is used as the initial state." Pool checkpoint width 1; DVE 4; Act 2.[HIGH/OBSERVED — d4_rand.h L52-60 + validator] - PCG32 — two u32 words (
rand_state[0..1]); ISA-defined (d4_rand.hL62-71) but POOL-unsupported (§5b).[HIGH — header text; no live arm] - PHILOX — counter-based: a 16-byte counter start, an 8-byte key, and a 4-byte counter
offset, "saved/restored unmodified for model checkpointing" (
d4_rand.hL73-83). Pool checkpoint width 7 (the 7 immediate/state words with theimm_state[7]==0constraint). num_active_channels(S1_RAND@13/D4_RAND@34) bounds the checkpoint to the live lane subset (validated againstPOOLING_NUM_CHANNELS);has_valid_rand_state_channelscouples the channel count to the algorithm.
4b. How it ties to the rand_algo fork
The rand_algorithm field is the rand_algo enum
{LFSR=0, PCG32=1, PHILOX=2, XORWOW=3} (mariana common.h L987-992). The same enum that
forks the draw path in the shared SetSeeds body forks the checkpoint here. From the
instruction-exact LFSR dispatch tree:
// Pool/Q7 RandSetState (MARIANA TIE), all addresses byte-pinned in rng-lfsr-dispatch.md
//
// SEQ front-end → 0xf0 ExtendedInstRandSetState (decode fn 0x87c0, log DRAM 0x1aa1)
// → Q7 RandSetState dispatcher 0xb5f4 (entry 48; log 0x1e80 "RandSetState: num_chans / rand_algo")
// reads rand_algorithm = i.s1_rand.rand_algorithm // [a1+12]
// → dispatcher 0xb640: algo_select = saltu(rand_algo, 1) // == (rand_algo == 0) [b67a]
// → shared SetSeeds 0xb6dc (THE FORK):
// b6e5: bbci a2, 0, 0xb6f5 // bit 0 of the stored algo flag at [a1+12]
// rand_algo == 0 (LFSR) → fall through → LfsrSetSeeds 0xb700 (entry a1,192)
// rand_algo == 3 (XORWOW) → branch → XorwowSetSeeds(TIE) 0xb744 (entry a1,0x400)
//
// RandGetState (0x77) mirrors it:
// SEQ → 0xf0 ExtendedInstRandGetState (decode 0x8688, log 0x1a3f)
// → Q7 RandGetState dispatcher 0xb930 (log 0x1ee5)
// → shared GetSeeds 0xb9ec (fork bbci a2,0,0xba05):
// LFSR → LfsrGetSeeds (log 0x1f1d)
// XORWOW → XorwowGetSeeds(TIE) 0xba58 (entry a1,0x580, log 0x1f30)
So 0x77/0x78 are algo-parametric: the firmware reads rand_algorithm@12, runs the
{0,3} POOL gate (§5b), forks to the Xorwow-vs-LFSR seed body, and that body's per-lane state
geometry is the checkpoint payload. The frame sizes at each arm entry
(LfsrSetSeeds entry a1,192; XorwowSetSeeds(TIE) entry a1,0x400;
XorwowGetSeeds(TIE) entry a1,0x580) are the inner per-lane buffers; the operationally relevant
checkpoint width is the validator element count (§4). [CARRIED from the LFSR + TIE pages]
CORRECTION —
LfsrSetSeeds 0xb700/XorwowSetSeeds(TIE) 0xb744are documented on the LFSR dispatch page, not the TIE page. The TIE-Xorwow page maps both SET arms to the shared entry0xb6dcand lists only the arm log xrefs (0xb716LFSR /0xb75aXorwow). Cite the LFSR page for the0xb700/0xb744arm entries.
5. The dispatch surface — SEQ → 0xf0 ExtendedInst → per-engine body
5a. The front-end is the NX/SEQ sequencer
The dispatch surface is SEQ (the NX sequencer front-end), which validates the operand and
then reaches the per-engine kernel body via the 0xf0 extended-instruction escape — the
seed-state ops are not in the Q7KIT EXTISA table directly. The string sweep over
libnrtucode_internal.so confirms the chain:
| string | count | role |
|---|---|---|
S: RandGetState / S: RandSetState | 11 / 11 | the SEQ front-end (present on every gen incl. SUNDA) |
ExtendedInstRandGetState / ExtendedInstRandSetState | 8 / 8 | the 0xf0 escape registration on the per-engine kernel_info table |
RandGetState / RandSetState | 26 / 26 | total (front-end + decode + dispatcher logs + bodies) |
XorwowGetSeeds / XorwowSetSeeds | 7 / 7 | the Xorwow seed bodies ((SW) cayman + (TIE) mariana+) |
LfsrGetSeeds / LfsrSetSeeds | 5 / 5 | the LFSR seed bodies (mariana+ only — zero on sunda/cayman) |
not currently supported on POOL | 6 | the {0,3} algo gate (§5b) |
[HIGH/OBSERVED]
The observed dispatcher log formats are verbatim:
P%i: Decode : ExtendedInstRandGetState
P%i: ExtendedInstRandGetState : num_tensor_elements = %d
P%i: RandGetState : num_chans = %0d : rand_algo = 0x%x
P%i: XorwowGetSeeds(SW)
P%i: XorwowGetSeeds(TIE)
P%i: LfsrGetSeeds
P%i: Xorwow(TIE) : Initializing XORWOW state in DRAM scratch
5b. The {0, 3}-algo POOL gate
The SEQ front-end validates rand_algo ∈ {0=LFSR, 3=XORWOW}; the other two enum values
(1=PCG32, 2=PHILOX) hit the gate string (observed verbatim, 6 occurrences):
S: RandGetState : rand_algorithm(0x%x) not currently supported on POOL
S: RandSetState : rand_algorithm(0x%x) not currently supported on POOL
So on POOL only LFSR + Xorwow state save/restore is wired; PCG32/Philox are ISA-defined but
POOL-unsupported. [HIGH/OBSERVED — gate at 0x301b]
GOTCHA — the host validator is broader than the wired POOL handler. Philox is a legal arm in both
legal_combinationsvalidators (the 7-word Pool/Philox arm), yet the POOL firmware gate rejectsrand_algo==2at runtime with the "not currently supported on POOL" string. The compile-time legal set (host ISA validator) and the runtime-wired handler set (POOL firmware) are not identical — Philox is admissible to the validator but dead on the POOL body.
5c. The same opcode has two engine bodies
The engine discriminator is the host validator's NeuronEngine argument, which selects the legal
(algo, state-width) set. The same opcode 0x78 has a Pool body (0xb5f4, §4b) and a
DVE body (0xebe0); the engine field of the instruction picks which. The DVE
RandSetState body is registered in the DVE kernel_info table immediately alongside Rand2 and
Exponential — confirmed in Rand2:
// DVE kernel_info registration stubs (consecutive), from rand2.md §5a:
230e: const16 a2, 0xebe0 // handler 0xebe0 = "S: RandSetState" (the DVE RandSetState body)
232a: const16 a2, 0xf2cc // handler 0xf2cc = "S: Rand2"
2346: const16 a2, 0xf698 // handler 0xf698 = "S: Exponential"
[HIGH/OBSERVED stub; MED funcVA byte edge]
NOTE — the device-side VAs are device VAs, not host symbols. The dispatcher/seed VAs (
0xb5f4,0xb930,0xb6dc,0xb9ec,0xb744,0xba58,0xb700,0xebe0) are Q7/DVE ucode addresses inside the embedded blob, recovered with the nativextensa-elf-objdump(XTENSA_CORE=ncore2gp) on the committed Xorwow/LFSR pages. They do not appear in the host-x86 IDA function DB oflibnrtucode_internal.so(host text spans0x9b01a0–0x9bb600) — the strings for these routines are in.rodata, the VAs are CARRIED from the device disassembly on the sibling pages.[VAs CARRIED; strings HIGH/OBSERVED]
6. Per-generation presence — opcode vs handler vs validator surface
The opcode is // Y on all four gens, but two finer surfaces lag it: the host validator's
legal-combination set (which engines/algos are admissible) and the runtime handler body
(which algo seed save/restore code actually ships). Header arm-counts and the ucode string
sweep agree.
| gen | opcode | validator engine(s) | legal arms (set / get) | rand_algo enum | RNG handler bodies present |
|---|---|---|---|---|---|
| SUNDA (v2) | // Y | Pool only (fixed arg) | 2 / 1 | LFSR, PCG32, PHILOX (no XORWOW) | none wired — SEQ string + 0xf0 decode exist, no algo body |
| CAYMAN (v3) | // Y | Pool only (fixed arg) | 3 / 2 | + XORWOW | XorwowSet/GetSeeds(SW) (SW path); no LFSR |
| MARIANA (v4) | // Y | Pool + DVE + Act (e arg) | 8 / 7 | full 4-value | XorwowSet/GetSeeds(TIE) + LfsrSet/GetSeeds + DVE RandSetState 0xebe0 |
| MAVERICK (v5) | // Y | Pool + DVE only (e arg) | 7 / 6 | full 4-value | same TIE + LFSR; Act arm dropped |
[HIGH/OBSERVED]
Two byte-grounded structural facts make this table exact:
- SUNDA's
RAND_ALGORITHMenum is truncated.neuron_sunda_arch_isa/tpb/common.hL875-877 defines onlyLFSR=0, PCG32=1, PHILOX=2— noXORWOW=3— and theRAND_SRCenum has onlyRNG_LFSR=0, RNG_PHILOX=2(noRNG_XORWOW, noOUTPUT_CVT_LFSR). SUNDA's only legal combination is Pool + Philox (d4_rand.hGET elem_cnt 7;s1_rand.hSET 2 Philox arms), and there is no wired Xorwow/LFSR POOL body. So on SUNDA the op exists at the ISA/decode layer but has no working save/restore body. - The validator call signature encodes the engine surface. SUNDA/CAYMAN call the validator
with a fixed
NeuronEngine::Poolargument (s1_rand.hL54 /d4_rand.hL147); MARIANA/ MAVERICK take the engineeas a parameter (rand_set_state_legal_combinations(i, e)), and their arms branch one == Pool | DVE | Act. That is the concrete encoding of "Pool-only on sunda/cayman, multi-engine on mariana+."
CORRECTION — MAVERICK is Pool+DVE, not the full Pool+DVE+Act. Header arm-count (
s1_rand.h7 set /d4_rand.h6 get) is exactly one fewer than MARIANA's (8/7). The missing arm is the Act-engine LFSR arm (e == NeuronEngine::Act,OUTPUT_CVT_LFSR, 2 words): present on MARIANA (s1_rand.hL118,d4_rand.hL243), absent on MAVERICK (zeroNeuronEngine::Actmatches in either MAVERICK header). The Act LFSR state-checkpoint arm is a MARIANA-only feature.
Tonga (NeuronCore-v1) note. The V1 (tonga) header set ships no s1_rand.h/d4_rand.h
and no RAND_GET_STATE/RAND_SET_STATE opcodes — this op family begins at SUNDA (v2).
[HIGH/OBSERVED — arch-isa/tpb/ absence]
7. The two RNG-state domains — GpSimd-RNG vs PE-SR-RNG
There are two physically and architecturally distinct RNG state domains. 0x77/0x78
belong to the first; 0x08 PeManageSeed to the second. They share the word "seed/state" only.
7.1 Domain A — GpSimd / datapath RNG (0x77 / 0x78, this page)
- Engine: Pool / DVE / Act vector datapath.
- State: the per-lane PRNG state in DRAM/SBUF scratch — Xorwow 6w | LFSR 1w | PCG32 2w | Philox 7w on Pool; wider on DVE (Xorwow 24, LFSR 4); Act LFSR 2.
- Algorithm:
rand_algo-selected{LFSR, PCG32, PHILOX, XORWOW}. - Op family:
RAND (0x76)/RAND2 (0xe2)advance;RAND_GET_STATE (0x77)/RAND_SET_STATE (0x78)checkpoint;SET_RNG_SEEDpseudo (§7.3) seeds.
7.2 Domain B — PE stochastic-rounding RNG (0x08 PeManageSeed)
From PE Matrix-Multiply Path:
- Opcode:
NEURON_ISA_TPB_OPCODE_PE_MANAGE_SEED = 0x08(// Y,common.hL163); v4+ only. - Engine: PE systolic array (TensorE).
- State: the PSUM fp32→bf16 stochastic-rounding seeds — not a per-cell PRNG. (NC-v4 keeps thousands of 32-bit seeds across the PSUM banks.)
- Struct:
NEURON_ISA_TPB_S2S1D2_PE_SEED_STRUCT(sizeof==64, compile-verified). - Modes:
NEURON_ISA_TPB_PE_SEED_MODE { NONE = 0, LOAD_SEED = 1, SAVE_SEED = 2 }(common.hL1132-1136). - Consumer: matmul PSUM drain to BF16.
[HIGH/OBSERVED — pe-matmul.md, common.h]
CORRECTION — use the enum, not the prose, for
PE_SEED_MODE. Thes2s1d2_pe_seed.hfield comment reads "LoadSeed (value of 0) / SaveSeed (value of 1)", but the authoritative C enum isNONE=0, LOAD_SEED=1, SAVE_SEED=2. The prose comment is off by one; trust the enum.
The decisive distinction: different opcode (0x08 vs 0x77/0x78), different engine (PE vs
Pool/DVE/Act), different struct (S2S1D2_PE_SEED vs D4_RAND/S1_RAND), different state (PSUM
SR seeds vs the algo PRNG state), different purpose (deterministic stochastic-rounding dither vs
user-RNG reproducibility). Do not conflate them.
7.3 The lesser cousin — SET_RNG_SEED (pseudo 0xd0)
SET_RNG_SEED is a pseudo opcode (NEURON_ISA_TPB_OPCODE_PSEUDO_SET_RNG_SEED = 0xd0,
mariana common.h L284; sunda L277), NRT-translated, struct
NEURON_ISA_TPB_PSEUDO_SET_RNG_SEED_STRUCT (sizeof==64, compile-verified:
seed_src@12, seed@16, from aws_neuron_isa_tpb_pseudo_set_rng_seed.h). Its operand is
seed_src and a single 4-byte seed@16 (IMM_VAL); the header comment reads "sets RNG
seed for engine; Only DVE supported for now." It seeds domain A (one-shot init) and is
lowered by NRT into a real op — it is not a state checkpoint and not 0x77/0x78.
8. The closed RNG opcode surface
With 0x77/0x78 decoded, the datapath-RNG (domain A) opcode surface is closed:
| op | name | struct | flag | role | page |
|---|---|---|---|---|---|
0x4D | RNG | (POOL) | YYYY | POOL Rng(XORWOW) draw handler | Xorwow SW / TIE |
0x76 | RAND | D4_RAND | nnnn | legacy general-HW draw (dormant) | Rand2 |
0x77 | RAND_GET_STATE | D4_RAND | YYYY | SAVE generator state | this page |
0x78 | RAND_SET_STATE | S1_RAND | YYYY | RESTORE generator state | this page |
0xE2 | RAND2 | D3_RAND | YYYY | modern DVE draw (Uniform) | Rand2 |
0x7F | DROPOUT | S3D3_DROP | YYYY | inline-RNG consumer (LFSR arm) | Dropout |
pseudo 0xd0 | SET_RNG_SEED | PSEUDO_* | — | one-shot seed (NRT-lowered) | §7.3 |
The rand_algo enum {LFSR=0, PCG32=1, PHILOX=2, XORWOW=3} (the dispatch fork),
the draw kernels (0x4D/0x76/0xe2 + Dropout), the seed-init pseudo (0xd0), and now the
state-checkpoint pair (0x77/0x78) account for every datapath-RNG opcode in the four-gen
ISA. The PE stochastic-rounding seed op (0x08, domain B) is a separate subsystem
(PeManageSeed). [HIGH/OBSERVED]
9. Walls and residual uncertainty
- The handler bodies' inner state-write/advance micro-ops live in FLIX-desync'd Q7/DVE bundles.
The flat DEBUG IRAM has no
.xt.propproperty table (the project-wide FLIX-desync wall the Xorwow/LFSR pages hit). The dispatcher entries, the fork instructions (bbci,saltu), the log strings, the frame sizes, and the call edges are byte-pinned (HIGH); the per-word shift/xor inside the seed bodies is not byte-recoverable (LFSR taps LOW/UNRECOVERED). Decoding the checkpoint dispatch + struct + semantics does not require the desync'd inner bundles: the state width/format come from the host validators (HIGH), the dispatch from the pinned entries (HIGH).[desync flagged; not needed for this page] - The DVE
opcode→funcVAdescriptor literal (the byte binding0x78 → 0xebe0) is in the runtime-bound kernel-descriptor region. The funcVA0xebe0body +"S: RandSetState"name string are HIGH/OBSERVED; the table→funcVA byte edge is MED/out-of-carve.[flagged] - The exact TIE Xorwow inner state-buffer byte size on POOL (the
entry a1,0x400/0x580frames) is MED (obscured by desync; inherited0x180=384-byte geometry from the SW path). The operationally relevant checkpoint width is fixed by the validator at 6 words / Pool (HIGH), which overrides the MED inner-buffer figure for the0x77/0x78operand.[reconciled: validator width HIGH] - The Xorwow Marsaglia seed constants and Weyl increment are CARRIED from the
SW path; they are referenced here, not re-derived.
[CARRIED]
10. Confidence summary
| area | tag |
|---|---|
The names (0x77 GET / 0x78 SET), // Y all four gens, enum order | HIGH / OBSERVED |
Struct bindings (instruction_mapping.json) + S1_RAND/D4_RAND compile-verify (sizeof 64, offsets) | HIGH / OBSERVED |
Per-(engine, generator, algorithm) state-width table (s1_rand.h/d4_rand.h arms) | HIGH / OBSERVED |
Dispatch chain (SEQ → 0xf0 ExtendedInst → Pool/DVE body), fork, logs, string-sweep counts | HIGH / OBSERVED |
{0,3} POOL gate; UINT32 (0x9) dtype | HIGH / OBSERVED |
| Per-gen presence (SUNDA-none / CAYMAN-XORWOW / MARIANA full / MAVERICK Pool+DVE) | HIGH / OBSERVED |
Two-domain (GpSimd-RNG vs PE-SR-RNG 0x08) + pseudo 0xd0 distinction | HIGH / OBSERVED |
Device-side dispatcher/seed VAs (0xb5f4…0xebe0) | CARRIED (device disasm, sibling pages) |
DVE opcode→funcVA descriptor byte; exact TIE inner state-buffer size | MED / out-of-carve |
| LFSR feedback taps + inner per-word state-advance micro-ops (FLIX-desync) | LOW / UNRECOVERED |