31.5V IV: Instruction Formats, Masking & Element Taxonomy

Part III Linux boot: recommended Vol. I (Unprivileged) pp. 292–296 · ~3 min read

The whole extension fits in three major opcodes: loads and stores squat in LOAD-FP/STORE-FP (repurposing the FP immediate bits), everything else lives in the new OP-V (1010111), where funct3 selects the operand pattern:

funct63126vm25vs22420vs1 / rs1 / imm51915funct31412vd / rd117101011160OP-V arithmetic format (OPIVV shown)
Click a field for its role.

Scalars come from immediates, x-registers, f-registers, or element 0 of any vector register (any LMUL). The f-on-v overlay was deliberately rejected — register pressure, calling convention, fast-scalar-FP design, and Zfinx compatibility all argued for separate files.

EEW/EMUL and the overlap rules

Every operand carries an effective width and multiplier — usually EEW=SEW, EMUL=LMUL, but widening ops write EEW=2·SEW at EMUL=2·LMUL (and narrowing reads the same). Groups are named by their lowest register; EMUL > 8 is reserved. One register may not be read at two different EEWs in one instruction. Destination/source overlap is legal only when:

Overlap constraints (violations = reserved encodings; designed for resumable exceptions WITHOUT renaming)
Allowed when
Same EEWAnywhere — ordinary in-place operations.
Destination narrowerOverlap only at the LOWEST register of the source group: vnsrl.wi v0, v0, 3 legal; destination v1 reserved.
Destination widerSource EMUL ≥ 1 and overlap only at the HIGHEST register: at LMUL=8, vzext.vf4 v0, v6 legal; source v0/v2/v4 reserved.
Mask register v0 (EEW=1)A masked instruction’s destination may not overlap v0 — unless the result IS a mask (compares) or a reduction scalar.
Dotted-underlined cells have explanations — click one.

Overlapping different-EEW cases execute tail- and mask-agnostic regardless of vtype — the old values are architecturally gone.

The element taxonomy

Every destination index falls into exactly one set: prestart (< vstart: never faults, never writes), body — split into active (mask on: computes, faults, writes) and inactive (mask off: vma policy) — and tail (≥ vl: vta policy). When vstart ≥ vl there is no body and nothing writes (even agnostic fills) — though instructions producing x/f-register results still deliver them, vl=0 included. Slides and gathers may read past vl; out-of-VLMAX source reads return 0.

Hardware Designer Notes

The overlap rules are the resumability contract: verify them as a matrix (EEW relation × register positions), because compilers lean on the legal corners (in-place narrowing especially) and reserved corners must trap, not corrupt.

Minimal Linux-boot hart MUST

  • Enforce every reserved-encoding rule (group alignment, EEW-conflict, overlap, EMUL>8) with traps — software probes these
  • Implement the element-taxonomy predicate exactly; active(x) gates exceptions as well as writes, so a masked-off lane must suppress its page fault
  • Handle the vstart ≥ vl no-write case including the scalar-result exception

MAY simplify / trap-and-emulate

  • Decode the seven funct3 patterns into a uniform internal op with an operand-source mux — the format regularity is deliberate

Check yourself — formats, masking, element sets

1.Why is vnsrl.wi v0, v0, 3 legal at LMUL=1 but a destination of v1 reserved?

2.How is masking encoded, and which register supplies the mask?

3.Classify element x during execution: vstart=2, vl=6, VLMAX=8, v0.mask = 0b10101010. What are elements 1, 3, 4, and 7?

4.Why do scalar operands live in element 0 of a vector register (for .vs forms) rather than overlaying f-registers on v-registers?

4 questions