Skip to content

VPU(Vector-ALU)Slot

本页所有地址都适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,未 strip)。.text.rodata VMA 等于其文件偏移。其他 libtpu 构建会不同。

摘要

VPU 是 TensorCore 的逐 lane 向量 ALU:它在架构上的 8 sublanes × 128 lanes = 1024-element 向量寄存器上执行逐元素算术。在 VLIW bundle 中,它表现为一个或多个 VectorAlu* 子 bundle;重新实现者必须序列化该 slot,才能驱动向量 add/mul/min/max/shift/select/compare/convert/pack,并把 transcendental 推入 extended-unary pipeline。不同于 SSA 后端中 scheduler 在运行时追踪 hazard,TPU bundle 就是 issue packet:encoder 把每个存在的 VALU slot 放入 bundle byte buffer 中按代固定的 bit offset;缺失 slot 用 never-execute predicate 填充。不存在逐指令 header;opcode 立即数同时选择操作,并且在较老代际上还选择 vector-mask register 或 transcendental function。

VPU slot 不是单一 wire format,而是六种格式的家族。存在两条 encoder lineage。Jellyfish 及其字节相同的变体 Dragonfish(EncoderJf 路径)通过直接 and/shl/or 位操作,把 VALU word 打包为 64 位值并 OR-merge 到 bundle。Pufferfish 和所有 v5+ 代际(Viperfish、Ghostlite、6acc60406)则使用统一的表驱动 BitCopy(dst, dst_bit, src, src_bit, nbits) primitive(@0x1fa0a900),由按 opcode keyed 的 jump table 到达每个 opcode 的 Encode<gen>VectorAluN<Op> helper 来驱动。沿 lineage 发展,slot 数量从 2 → 4,opcode 字段从 6 → 7 → 8 bits 加宽,逐 slot predicate 字段从 5 → 4 → 2 bits 缩小,单个 XLU(transcendental)变成一对;每个变化都是对更宽计算结构的有意响应,而不是 padding。

本页把该 slot 作为重新实现目标进行记录:opcode enum 及其 op-family 分组;opcode / destination / 两个 source / Y-operand selector / predicate 的精确 bit 位置,全部锚定到已验证的 BitCopy 立即数;lane 几何;Y-operand(source-B)选择器模型;EUP/XLU push-pop 协议;predicate 和 vector-mask 寄存器文件;以及 JF→GF 演化。

重新实现的契约是:

  • 两个 encoder 家族和通用 BitCopy bit-packing primitive:何时直接打包,何时表分派。
  • 每代字段布局:opcode、destination vreg、两个 source vreg、5 位 Y-operand selector 和 predicate 字段,在 bundle 内的精确 bit offset。
  • 每代 VectorAluOpcode 空间(6/7/8 位;63 / 131-op enum),按家族分组,加上 VectorAluYEncoding(0..31)source-B 模型。
  • lane 几何(通用 8×128)和 EUP/XLU push-pop,包括 v5+ 对 push 限制在 VALU slot 3。
Slot protoVectorAluInstruction (JF/DF/PF) / TensorCoreVectorAlu[0..3] (v5+)
通用 bit-packerBitCopy(void*, int dst_bit, const void*, int src_bit, int nbits) @ 0x1fa0a900 (_Z7BitCopyPviPKvii)
Opcode enumVectorAluOpcode dense 0..62VectorAluOpcode_descriptor @ 0x1fa1fca0);v5+ proto TensorCoreVectorAlu.<Op>H(131 ops)
Y-operand enumVectorAluYEncoding dense 0..31@0x1fa1fc40)— vreg / VS0-2 / IMM0-5 / hardwired constants
Lane 几何8 sublanes × 128 lanes = 1024 elements / vreg(所有代际)
寄存器文件v0..v1023 架构寄存器;6 位 slot window(PF/v5+)→ 每 slot 可直接寻址 64 个
XLU push-popVALU push → EUP pipeline;VectorResult PopEupResult 在一个或多个 bundle 后 pop;single-issue("1 XLU Busy"

两个 Encoder 家族

目的

重新实现者的第一个决定,是目标代际属于哪条 encoder lineage,因为两条路径会从同一条逻辑 VALU 指令产生互不兼容的 wire format。lineage 决定字段是由手写 shift 放置,还是由通用 copy primitive 放置,也决定每个 opcode 是否有自己的 emitter。

算法

Jellyfish 路径内联打包 slot。EncoderJf::EncodeVectorAluInstruction@0x1e864f00)会按宽度 mask 每个字段并 shift 到 64 位 accumulator 中的位置,然后把 accumulator OR 到 bundle buffer:

c
function EncoderJf_EncodeVectorAluInstruction(inst, slot, bundle):  // @0x1e864f00
    if slot > 1: fatal("slot < kMaxVectorAluSlotsPerBundle")  // only 2 VALU lanes
    pred = inst.predicate & 0x1f                  // 5-bit predicate  (and 0x1f)
    op   = inst.opcode    & 0x3f                   // 6-bit opcode     (and 0x3f)
    if op >= 0x3e: error                           // opcode range 0..62 (cmp 0x3e=62)
    if op == 0x18 or IsEupOpcode(op): reserve_xlu()  // ProtoUtils::IsEupOpcode @0x1e875900
    if slot == 0:                                  // lane 0 → struct 0x1D window (abs 136..167)
        bundle[0x1D] |= (Vx  & 0x1f) << 0          // Vx  @ abs 136
                      | (op  & 0x3f) << 5          // op  @ abs 141  (the "32 *" multiply)
                      | (pred & 0x1f) << 11         // pred@ abs 147
    else:                                          // lane 1 → struct 0x16 cross-word (abs 90..127)
        word  = (yenc & 0x1f) << 10                // Y-enc @ abs 90
              | (Vx   & 0x1f) << 25                // Vx    @ abs 105 (binary-op path)
              | (op   & 0x3f) << 30                // op    @ abs 110 (shl 0x1e)
              | (pred & 0x1f) << 36                // pred  @ abs 116
              | (dst  & 0x1f) << 41                // dst   @ abs 121
        bundle[0x16] |= word                        // OR-merge into 56-bit window
    EncodeVectorAluYEncoding(inst, slot, bundle)   // @0x1e864be0 — resolves Y-operand source
```text

Pufferfish 和 v5+ 路径改为经过逐 slot `Encode` dispatcher:它按 opcode 走 jump table 并 tail-call 逐 op helper;每个字段都由 `BitCopy` 写入:

```c
function VxcTensorCoreVectorAlu0Encoder_Encode(proto, out_span):  // VF @0x1eef8a80
    op = proto.opcode                              // read at proto +0x50
    BitCopy(out, 306, &proto.predicate, 0, 4)      // 4-bit predicate @ bit 306 (mov esi,0x132)
    BitCopy(out, 299, &op,             0, 7)       // 7-bit opcode    @ bit 299 (mov esi,0x12b)
    if op >= 0x80: error                           // opcode range 0..128 (cmp 0x80=128)
    helper = jump_table[op]                        // table @ rodata 0xb84600c
    helper(out, proto)                             // e.g. EncodeTensorCoreVectorAlu0VectorFloatAdd

BitCopy 本身是每个 v5+ 字段写入都会汇入的单一 primitive:rdi=destination buffer,esi=bundle 内 destination bit offset,rdx=source value 指针,ecx=source bit(几乎总是 0),r8d=bit count。它把 src[src_bit..] 中的 nbits 复制到 dst[dst_bit..],所以本页每个字段 offset 都表现为一次 call 0x1fa0a900 之前紧邻的 mov esi, <bit> / mov r8d, <width> 对。

函数映射

函数地址角色
BitCopy(void*,int,const void*,int,int)0x1fa0a900通用 v5+/PF bit-packer
EncoderJf::EncodeVectorAluInstruction0x1e864f00JF/DF 直接打包 VALU encoder
EncoderJf::EncodeVectorAluYEncoding0x1e864be0JF Y-operand selector encode
EncoderJf::EncodePredication<VectorAluInstruction>0x1e864000JF 逐 slot predicate encode
EncoderJf::EncodeBundleInternal0x1e86c7c0对每个存在的 slot 调用 VALU encoder
ProtoUtils::IsEupOpcode(VectorAluOpcode)0x1e875900JF EUP-push 分类器
pxc::isa::TensorCoreVectorAlu0Encoder::Encode0x1ed45060PF VALU0 dispatcher(struct …Alu0
pxc::isa::TensorCoreVectorAlu1Encoder::Encode0x1ed68d80PF VALU1 dispatcher(struct …Alu1
vxc::isa::TensorCoreVectorAlu{0..3}Encoder::Encode0x1eef8a80 / 0x1ef1c500 / 0x1ef3f120 / 0x1ef62880VF 4 个 VALU dispatcher(共享 struct)
gxc::glc::isa::TensorCoreVectorAlu0Encoder::Encode0x1f250160Ghostlite VALU0 dispatcher
gxc::gfc::isa::TensorCoreVectorAlu0Encoder::Encode0x1f8b53c06acc60406 (GF) VALU0 dispatcher
gxc::{glc,gfc}::isa::SparseCoreTecVectorAlu{0..2}Encoder::Encode0x1eaa4880… / 0x1ec11100…SparseCore TEC 3 个 VALU slot

特例 — Pufferfish 给 VALU0 和 VALU1 使用不同 struct 类型TensorCoreVectorAlu0 vs TensorCoreVectorAlu1),且 VALU1 接受更宽 opcode 范围:cmp rcx,0x43(67)对比 VALU0 的 cmp rcx,0x3e(62)。VALU1 带有一些 VALU0 没有的 op。从 Viperfish 开始,四个 slot 共享一个 TensorCoreVectorAlu struct 和一个 op 范围,所以重新实现可使用单一 encoder template;在 Pufferfish 上则不能。


Bit-Field 布局 — 按代际

目的

这是 byte-level wire format:每个字段位于 bundle byte buffer 的哪里。本页所有 bit position 都是 LSB-first:bit 0 是 byte 0 的最低有效位,匹配 Bundle Model 全文使用并由 BitCopy packer 强制执行的约定(它从 LSB 编号的 dst_bit 起向上写 nbits)。encode 路径中不存在任何 MSB-first 排序。下面所有 v5+ offset 都直接读取自代表性 VectorFloatAdd / VectorF32Add helper 中的 BitCopy mov esi/mov r8d 立即数;Jellyfish offset 来自 EncodeVectorAluInstruction 中的 and/shl 立即数。

编码

无论代际,encoder 都读取一组统一 struct 字段。VALU 指令的 opcode 位于 proto +0x50;operand descriptor(destination / sources / Y-encoding)挂在 +0x48;逐 slot predicate 是自己的字段。

c
// Field reads (proto offsets, consistent across the v5+ helpers):
proto +0x50 : VectorAluOpcode   (the op immediate)
proto +0x48 : operand descriptor → { dst vreg, src0 vreg, Y-encoding, src1 vreg }
            : per-slot predicate field source
```text

**Jellyfish / Dragonfish**41-byte TC bundle,`EncoderJf::EncodeVectorAluInstruction` @ `0x1e864f00`)。直接 `and`/`shl`/`or`,*不是* `BitCopy`。两个 VALU lane 占用 328-bit bundle 中两个*独立* window,而不是一个重复 stride:lane 0(`slot == 0`)打包到 struct-`0x1D` window(绝对 bit 136..167),lane 1(`slot == 1`)打包到 struct-`0x16` cross-word window(绝对 bit 90..127)。每个 lane 内字段由字面 shift 常量放置;由于两个 window origin 不同,每个字段的绝对 bit 也随 lane 不同(raw shift 共享相对布局)。opcode 被 mask 为 `and 0x3f`(6-bit,范围 0..62,带 `cmp 0x3e` guard),predicate 为 `and 0x1f`(5-bit);register 和 Y-encoding 字段是 5-bit window。Dragonfish 共享 `EncoderJf` 和 `JellyfishCodecMetadata`,因此字节相同。交叉检查出的绝对位置(LSB-first,也列在 [Jellyfish 41-bit Bundle](bundle-jf-41b.md) 中):

| 字段 | 宽度 | Raw shift | Lane 0 bit(struct `0x1D`) | Lane 1 bit(window `0x16`) |
|---|---|---|---|---|
| Y-encoding(src1 vreg) | 5-bit | `<< 10` | —(slot-3 路径) | 90 |
| Vx(src0 vreg) | 5-bit | `0` / `<< 25` | 136 | 105 |
| opcode | 6-bit | `<< 5` / `<< 30`(`shl 0x1e`) | 141 | 110 |
| predicate | 5-bit | `<< 11` / `<< 36` | 147 | 116 |
| dst vreg | 5-bit | `<< 41` |(在 `0x1D` tail 中) | 121 |

> **陷阱 — JF VALU 是两个不同 window,不是 stride。** Lane 0 写 byte `0x1D`/qword2;lane 1 写 byte `0x16` 处的 56-bit cross-word(组装为 `dword[0x16] | word[0x1A]<<32 | byte[0x1C]<<48`)。若重新实现像 v5+ slot 那样通过给 lane 0 加固定 offset 来推导 lane 1,会把每个 lane-1 字段都放错。`EncodeVectorAluInstruction` 中的 shift 常量是相对于各 lane window origin(lane 0136,lane 180)的,因此同一逻辑字段会落到不同绝对 bit,例如 opcode 在 lane 0 的 bit 141 和 lane 1 的 bit 110

**Pufferfish**51-byte TC bundle)。VALU0 `Encode` @ `0x1ed45060`,VALU1 @ `0x1ed68d80`。`BitCopy` 驱动,6-bit register 字段(64-window)。

| 字段 | 宽度 | VALU0 bit | VALU1 bit |
|---|---|---|---|
| predicate | 5-bit | 236 (`0xec`) | 193 (`0xc1`) |
| opcode range | 6-bit | `cmp 0x3e` (0..62) | `cmp 0x43` (0..67) |
| dst vreg | 6-bit | 230 (`0xe6`) ||
| immediate(逐 imm-op) | 16-bit each | 272 / 288 / 304 / 320 / 338 ||
| NOP fill || predicate ← `0x1f` (`kNeverExecute`) | same |

**Viperfish**64-byte TC bundle)。四个 slot,共享 struct**34-bit per-slot stride**。VALU0 `Encode` @ `0x1eef8a80`;代表性 `VectorFloatAdd` helper(op `0x0c`)@ `0x1eefa2c0`:

| 字段 | 宽度 | VALU0 bit | 来源 |
|---|---|---|---|
| opcode | 7-bit | 299 (`0x12b`) | `mov esi,0x12b; r8d,7` |
| dst vreg | 6-bit | 276 (`0x114`) | `mov esi,0x114; r8d,6` |
| src vreg | 6-bit | 282 (`0x11a`) | `mov esi,0x11a; r8d,6` |
| src vreg | 6-bit | 293 (`0x125`) | `mov esi,0x125; r8d,6` |
| Y-encoding | 5-bit | 288 (`0x120`) | `mov esi,0x120; r8d,5` |
| predicate | 4-bit | 306 (`0x132`) | `mov esi,0x132; r8d,4` |
| opcode range || `cmp 0x80` (0..128) | dispatcher |

四个 predicate 字段位于 bit 306 / 272 / 238 / 204(VALU0..3),统一 −34-bit 步进,所以 slot 占据 512-bit bundle 上部三分之一中的 `{opcode 7 + dst 6 + 2 src 6 + Y-enc 5 + pred 4} = 34` bit。

**Ghostlite**64-byte TC bundle)。VALU0 `Encode` @ `0x1f250160`:predicate `BitCopy(…,309,…,4)`(`0x135`),opcode `BitCopy(…,302,…,7)`(`0x12e`),dispatch `cmp 0x83`(0..131)。6-bit register 字段,与 Viperfish 相同 template,但因加宽的 slot start 整体 +3 bit。

**6acc60406 (GF)**64-byte TC bundle)。VALU0 `Encode` @ `0x1f8b53c0`;代表性 `VectorF32Add` helper @ `0x1f8b7860`:

| 字段 | 宽度 | VALU0 bit | 来源 |
|---|---|---|---|
| opcode | **8-bit** | 293 (`0x125`) | `mov esi,0x125; r8d,8` |
| dst vreg | 6-bit | 276 (`0x114`) | `mov esi,0x114; r8d,6` |
| src0 vreg | 6-bit | 270 (`0x10e`) | `mov esi,0x10e; r8d,6` |
| src1 vreg | 6-bit | 287 (`0x11f`) | `mov esi,0x11f; r8d,6` |
| Y-encoding | 5-bit | 282 (`0x11a`) | `mov esi,0x11a; r8d,5` |
| predicate | **2-bit** | 301 (`0x12d`) | `mov esi,0x12d; r8d,2` |
| opcode range || `cmp 0x83` (0..131) | dispatcher |

> **陷阱 —** 6acc60406 (GF) 的 predicate 字段只有 2 bit,*不足以*命名 16 个 predicate register 之一。它在 `{pred_0, pred_1, always, never}` 之间选择:bundle 的两个 active dual predicate 由专用 `TensorCorePredicates` slot 写入,VALU slot 只选择两者中哪一个适用。把 2-bit 字段当作 4-register 索引的重新实现,会把每个 GF VALU op 的 predicate 都弄错。见 [Predicate Slot](slot-predicate.md)。

### 每代 Slot 位置

| Gen | Bundle | #VALU | Lane-0 opcode bit | Lane-0 pred bit | Pred width | Per-slot stride |
|---|---|---|---|---|---|---|
| Jellyfish (v2) | 41 B | 2 | 141(lane 1 op @110| 147(lane 1 @116| 5-bit | two windows (136 / 80) |
| Dragonfish (v3 var) | 41 B | 2 | alias of Jellyfish | alias of Jellyfish | 5-bit | two windows (136 / 80) |
| Pufferfish (v4) | 51 B | 2 |switch 分派) | 236; lane 1 @193 | 5-bit | distinct structs |
| Viperfish (v5p) | 64 B | 4 | 299 | 306 | 4-bit | 34 bits/slot |
| Ghostlite (v6e) | 64 B | 4 | 302 | 309 | 4-bit | ~34 bits/slot |
| 6acc60406 (TPU7x) | 64 B | 4 | 293 | 301 | 2-bit | ~34 bits/slot |
| SparseCore TEC | 64 B | 3 | `SparseCoreTecVectorAlu0..2`(同 template,SC bundle) || 4/2-bit | 未 leaf-decoded |

代际到 codename 的映射由 codec-metadata table 固定(见 [Bundle Model](bundle-model-overview.md)):`kJellyfish`=v2,`kDragonfish`=v3,`kPufferfish`=v4,`kViperfish`=v5p,`kGhostlite`=v6e,`k6acc60406`=TPU7x。二进制命名空间相应为 `jellyfish`(JF/DF,共享 proto)、`pxc`(PF)、`vxc`(VF)、`gxc::glc`(GL)、`gxc::gfc`(GF)。

---

## VectorAlu Opcode Enum — 按家族

### 目的

opcode 立即数选择操作。enum 有两个命名代际:dense Jellyfish `VectorAluOpcode`(`0..62`,63 个值)和 v5+ `TensorCoreVectorAlu.<Op>H` proto-message 集(Viperfish 上 131 个 op,Ghostlite/6acc60406132 个)。二者覆盖同一套逻辑能力;只有 dtype 拆分和 Vmsk 处理方式不同。这里按家族分组,而不是平铺转储;SparseCore TEC 142-op 枚举(同一批家族更细粒度的 dtype 拆分)在源码中是字节精确的,并在本节末尾概述。

### 编码

proto enum descriptor 及其 dense range 可从 mangled `NameOfDenseEnum` template 实例恢复:

```text
NameOfDenseEnum<VectorAluOpcode,      0, 62>  @ 0x22331a5863 op values
NameOfDenseEnum<VectorAluYEncoding,   0, 31>  @ 0x223dff4032 Y-selector values
NameOfDenseEnum<VectorExtendedOpcode, 0, 34>  @ 0x2239bce835 EUP/MXU staging ops
NameOfDenseEnum<VectorResultOpcode,   0,  2>  @ 0x2239bd003 pop ops

v5+ op 家族分组如下(代表性 proto 名;H 后缀 = v5+ proto-message 命名):

家族Op(代表)备注
Float arithmeticVectorFloatAdd, Subtract, Multiply, Max, Minf32/bf16 lanes
Float compareFloatEq/Neq/Gt/Gte/Lt/Lte, TotalLt/TotalLte, InfOrNan产生 vector mask
Integer arithmeticIntegerAdd/Subtract/Multiply/Carrys16/s32/u16/u32
Integer compareIntegerEq/Neq/Gt/Gte/Lt/Lte产生 vector mask
BitwiseBitwiseAnd/Or/Xor
ShiftLogicalShiftLeft/Right, ArithmeticShiftRight
Move / miscMove, Clamp, Classify, Relux, Ceiling, Floor
Bit countCountLeadingZeros, PopulationCount, ByteNez
ConvertConvertF32To{Bf16,Bf8,Hf16,If8,Int32}[Stochastic], ConvertInt32ToF32+ FP8/FP4 narrow,stochastic round
Mask genCreateMask, LaneId
SelectVectorSelectVmsk0..15, VectorSelectNotVmsk0..15(PF/VF)/ VectorSelect+VectorSelectNot(GL/GF)消费 Vmsk
Transcendental(EUP push)Reciprocal, ReciprocalSqrt, Tanh, ShiftedSigmoid, LogTwo, PowTwo, EupPushissue 到 XLU

特例 — Pufferfish 和 Viperfish 上的 32 个 VectorSelect[Not]Vmsk0..15 条目不是 32 个不同操作;它们是同一个 select op,只是 mask-register index(Vmsk0..15)被烘焙进 opcode。Ghostlite 和 6acc60406 把它们合并成单个 VectorSelect / VectorSelectNot opcode,并把 Vmsk index 移到独立字段(宽度未测量;很可能是 16 masks 的 4-bit — LOW)。重新实现必须知道目标代际使用哪种方案,否则要么会膨胀 opcode 空间,要么找不到 mask index。

lower 到这些 opcode 的 LLO IR mnemonic(几何后缀 .8x128 = 原生 vreg)在 .rodata 中确认了能力范围:vadd.8x128.{f32,bf16,s32,s16}vmul.8x128.{f32,bf16,u32,u16}(加上宽 vmul.u32.u64 slot-pair)、vand/vor/vxor/vandn.8x128.u32vshll/vshra/vshrlvcmp.{f32,f64}vsel.8x128.xlane tree-reduce 家族、vcvt.* convert 集(包括 .sr stochastic-round 和 FP8/FP4 narrow 类型)、vpack/vunpack sub-byte 家族,以及 transcendental vrsqrt/vrcp/vtanh/verf/vsinq/vcosq/vpow 和匹配的 .pop 形式。

注意 — SparseCore TEC vector ALU 以更细的 dtype 粒度运行同一套家族分类:Ghostlite TEC consumer 枚举 142 个 op(92 个 integer/float core,18 个 transcendental = 9 个家族 × {f32,bf16},32 个 quant pack/unpack),而 Viperfish TEC 为 95 个(dtype 合并 op,没有 cosq/erf/sinq)。这种拆分 — tanhtanh_f32 + tanh_bf16unpack_*_sublanes_*unpack_compressed_*_lanes_*_to_* — 是 SC TEC table 比 TensorCore proto enum 更大的原因;它在 SparseCore router analysis 中按 opcode 记录,而不在此处复述。


Lane 几何与 Operand Register File

目的

每个 VALU op 都作用于完整向量寄存器;几何是重新实现者布局 vreg 和推理 sub-byte packing 时必须复现的内容。

编码

原生 vreg 是 8 sublanes × 128 lanes = 1024 elements,所有代际通用(.8x128 mnemonic 后缀;HAL 访问按 (sublane, lane),例如 ReadVectorRegister(core, sublane, lane) @ 0x0e755c20)。小于 32-bit 的类型在 lane 内打包:

text
32-bit element :  8 × 128            = 1024 elements   (.8x128)
16-bit element :  8 × 128 × 2        (bf16/s16/hf16, two per 32-bit lane;  .8x128x2)
8-bit  element :  8 × 128 × 4        (s8/u8/e4m3/e5m2, four per lane;       .8x128x4)
4-bit / fp4    :  8 × 128 × 4 with sub-element packing
                 ("32x16x128 only supports fp4 element types")
```text

V5+ 还为 layout-inference pass 暴露更宽的物理布局(`16x128`、`8x256`、`4x8x128`、`8x8x128`、twisted/untwisted);这些是多 vreg *tile aggregation*,不是逐指令 1024-lane count 的变化。

架构寄存器文件是 `v0..v1023`(`TPURegStrings` 中 1024 个名称)。一个 VALU slot 编码一个 destination 和最多三个 source vreg;在 Pufferfish 和 v5+ 上每个都是 **6-bit 字段**(Jellyfish 上是 5-bit register-class window)。六位可直接寻址 64 个寄存器,所以每个 slot 看到的是 1024-name 文件的一个 *window*;每个 subtarget 的 `getVyEncodings(unsigned)` map 会把架构 vreg 翻译为 slot encoding(当某个 vreg 不可在该 slot window 中编码时返回 `0xffffffff`):

| Subtarget | `getVyEncodings` |
|---|---|
| `TPUBcSubtarget`(PF BarnaCore) | `0x13c58de0` |
| `TPUVfcSubtarget`(Viperfish) | `0x13c5ec20` |
| `TPUGlcSubtarget`(Ghostlite) | `0x13c60a20` |
| `TPUGfcSubtarget`(6acc60406) | `0x13c625a0` |

> **注意 —** window-map 内容(哪个架构 vreg 映射到哪个 6-bit slot code)尚未转储;lookup 形状和 `-1` sentinel 已确认,逐项 table 尚未确认。重新实现者必须在编码真实程序前恢复每代 window assignment。

---

## Y-Operand(Source-B)选择器

### 目的

二元 VALU op 的第二个 source 不是普通 vreg 字段;它由一个 5-bit `VectorAluYEncoding` 值选择,该值可命名 vreg、共享 vector-source read port、immediate slot 或 hardwired constant。这一机制让常见 scale/bias 算术无需消耗 immediate slot。

### 编码

该字段为 5-bit(`VectorAluYEncoding` dense `0..31`,`@0x1fa1fc40`),由 operand-descriptor `+0x20` 经 `BitCopy` 写入。32 个值(从 `.rodata` `VECTOR_ALU_Y_*` 字符串逐字确认):

| 组 | 值 | 含义 |
|---|---|---|
| Vreg | `VREG` | 显式 vector register(使用 src1 vreg 字段) |
| VS ports | `VS0`, `VS1`, `VS2` | bundle 共享 vector-source read port 0/1/2(v5+ 上为 4 个 port) |
| Float constants | `FLOAT_ONE`, `FLOAT_TWO`, `FLOAT_NEGATIVE_ONE`, `FLOAT_ZERO_POINT_FIVE` | hardwired `1.0`/`2.0`/`-1.0`/`0.5` |
| Integer constants | `INTEGER_ONE`, `INTEGER_NEGATIVE_ONE`, `ZERO` | hardwired |
| Immediate slots | `IMM0_ZERO`..`IMM5_ZERO`, `ZERO_IMM0`..`ZERO_IMM5`, `ONES_IMM0`..`ONES_IMM5` | 引用 bundle imm slots 0..5,带 zero/ones extension |
| Paired-slot wide | `IMM1_IMM0`, `IMM3_IMM2`, `IMM5_IMM4` | 两个 imm slot 融合成宽 immediate |

VS ports 是稀缺 bundle 资源:同一 bundle 中的多个 VALU slot 共享少量 read port,packer 的 `SlotTracker` 会把它们计为 bundling constraint。hardwired float constant 是 scaling 和 bias op 不消耗 immediate slot 的原因。

---

## XLU(Transcendental)Push-Pop

### 目的

Transcendental — `rsqrt`、`rcp`、`tanh`、`sigmoid`、`log2`、`pow2`,以及 mnemonic-pool 的 `erf`/`sin`/`cos`/`pow` — 不在 VALU slot 内完成。它们从 VALU slot 被 *pushed* 进 Extended-Unary Pipeline(XLU),并在一个或多个 bundle 后从 `VectorResult` slot 被 *popped*。重新实现者必须把它建模为带有结构性 single-issue hazard 的两指令协议,而不是单周期 op。

### 算法

```c
// STAGE 1 — PUSH (issued from a VALU slot)
//   VALU op = the XLU push.  Proto names: ReciprocalH / ReciprocalSqrtH /
//   TanhH / ShiftedSigmoidH / LogTwoH / PowTwoH / EupPushH (generic push).
//   IsEupOpcode(op) @0x1e875900 classifies which opcodes are pushes so the
//   packer reserves the XLU resource for this bundle.
//
// STAGE 2 — POP (issued one+ bundle later from a VectorResult slot)
//   VectorResult op PopEupResultH reads the XLU result into a dest vreg.
//   The .pop mnemonic suffix (vrsqrt.f32.pop, vrcp.bf16.pop, …) is this pop.

在 Viperfish 上,push 限制为 VALU slot 3:唯一 EUP-push helper 是 EncodeTensorCoreVectorAlu3EupPush@0x1ef6e400vxc anonymous namespace),它把 7-bit opcode 放到 bit 197(0xc5)、5-bit function selector 放到 bit 186(0xba)、6-bit source 放到 bit 191(0xbf)。因为 XLU 是 single-issue,只有 Alu3(而不是 Alu0/1/2)发起 push;transcendental helper 只存在于 Alu3 集。

XLU 是 single-issue 硬件;诊断字符串 "1 XLU Busy" 存在于 .rodata,bundle cost model 把 XLU 分配到 overlap-blended resource,因此 pipeline drain 按约 50% residual overlap 计费。Jellyfish 有 1 个 XLU;v5+ 代际有 2 个(packer 的 AddXluRequirements 会相应 reserve)。

注意 — 单独的 VectorExtendedOpcode enum(dense 0..34,35 个 op,@0x1fa1fd00)是 MXU / matmul staging 路径:MatrixMultiply<fmt>LoadMatrixRegister{Gmr,Lmr}LaneBroadcastLaneRotateLoadStagingUpperBlock。它不同于 VALU transcendental push,但共享同一个 EUP pipeline 和同一个 PopEupResult pop。见 MXU Slot

函数映射

函数地址角色
vxc::isa::EncodeTensorCoreVectorAlu3EupPush0x1ef6e400VF EUP push(仅 Alu3)
jellyfish::isa::ProtoUtils::IsEupOpcode0x1e875900对 EUP-push opcode 分类
proto::Arena::DefaultConstruct<gxc::glc::isa::TensorCoreVectorAlu_EupPush>0x1fb49c00Ghostlite EUP push proto
proto::Arena::DefaultConstruct<…TensorCoreVectorResult_PopEupResult>0x1fb55b40 (glc) / 0x1fb9e660 (gfc)result pop proto
proto::Arena::DefaultConstruct<pxc::isa::TensorCoreVectorResult{0,1}_PopEupResult>0x1fa86240 / 0x1fa86ac0PF dual result pop

Predicate 与 Vector-Mask Register Files

目的

两个独立寄存器文件会接触 VALU slot,而且很容易混淆。predicate 字段门控 slot 的 op 是否执行;vector maskVmsk)是 conditional select 的数据操作数。它们是不同文件。

编码

逐 slot predicate 字段宽度和 predicate register 数量:

GenPred widthVALU0 pred bit语义Pred regs
Jellyfish5-bit(packed word)0..14 reg,15 = always,31 = never15
Pufferfish5-bit236 (V0) / 193 (V1)same15(BarnaCore 上 16)
Viperfish4-bit30616 个 pred regs 之一16
Ghostlite4-bit30916 个 pred regs 之一16
6acc604062-bit301{pred_0, pred_1, always, never}16

v5+ subtarget 的 16-register 数量是已确认的 inline constant:getNumPredicateRegistersTPUVfcSubtarget@0x13c5f6e0)、TPUGlcSubtarget@0x13c615c0)、TPUGfcSubtarget@0x13c630e0)和 TPUBcSubtarget@0x13c59780)都返回 mov eax,0x10; ret。Jellyfish/Pufferfish-TC 使用 base TPUSubtarget 的 15 个计数。

vector-mask 文件是 16 个寄存器Vmsk0..15),不同于 predicate 文件。Compare op 产生 VmskVectorSelect 消费一个。每代 select opcode/field 拆分见上面的 opcode-enum 小节。

注意 — 6acc60406 (GF) 的窄 2-bit predicate 之所以可行,是因为完整的逐 bundle predicate-register 写入已从 VALU slot 移到专用 TensorCorePredicates slot。VALU slot 选择两个预写 dual predicate 中哪一个适用。精确的 2-bit value-to-meaning 映射(0=pred_03=never?)尚未解码 — LOW。


JF → GF 演化

该 lineage 是一个计算结构逐步加宽的连贯故事,而不是任意的逐代变动:

JF (v2)PF (v4)VF (v5p)GL (v6e)GF (TPU7x)
VALU slots22(不同 structs)444
Encoderdirect and/shl/orBitCopyBitCopyBitCopyBitCopy
Slot structshared proto,two windows (136 / 80)Alu0Alu1sharedsharedshared
Opcode bits6 (0..62)6 (V0 0..62 / V1 0..67)7 (0..128)7 (0..131)8 (0..131)
Register field5-bit window6-bit6-bit6-bit6-bit
Y-encoding5-bit5-bit5-bit5-bit5-bit
Predicate field5-bit5-bit4-bit4-bit2-bit (dual)
Predicate regs1515(16 BC)161616
Vmsk selectper-Vmsk opcodeper-Vmsk opcodeper-Vmsk opcodesingle op + fieldsingle op + field
XLUs11222

叙事如下:Pufferfish 保留两个 slot,但切换到表驱动 encoder 和 64-window register,把两个 slot 拆成不同 struct(VALU1 更宽),并加入 vmul.u32.u64 slot-pair wide multiply。Viperfish 翻倍到四个 slot,把 opcode 加宽到 7 bit,以容纳 FP8/FP4 convert + stochastic-round + sublane pack/unpack 集,predicate 缩窄到 4 bit,并加入第二个 XLU。Ghostlite 把 32 个 per-Vmsk select opcode 折叠成一个 op 加 mask 字段,并按 dtype 拆分 reciprocal。6acc60406 (GF) 把 opcode 加宽到 8 bit(留出空间;当前最大 131),并把逐 slot predicate 缩小到 2-bit dual-predicate selector,因为 predicate-register 写已移到专用 slot。

陷阱 — v5+ 上 EUP push 是 slot-3-specific,不是 slot-agnostic。Viperfish encoder 只把 push helper 暴露为 EncodeTensorCoreVectorAlu3EupPush(slot 3);single-issue XLU 只由 Alu3 发起。


未解码内容

  • 每个 PF/VF/GL/GF VALU op 的 leaf per-opcode 子字段 offset。binary-ALU / select / convert / pack-unpack / EUP-push template 已解码到精确 offset;其余 op 复用同一 template,仅 opcode 立即数变化,但特殊形式(sublane-masked pack/unpack、vmul.u32.u64 pair、CreateMaskLaneId)携带额外子字段,未逐 op 枚举。
  • index-ordered VectorAluOpcode value→name array(descriptor 和 dense 0..62 范围已定位;未遍历逐 index 名称)。
  • v5+ 131-op enum value→name 映射(op 名称是已确认集合;只有少数 opcode 立即数,例如 VectorFloatAdd = 0x0c,已确认 index)。
  • SparseCore TEC VectorAlu0..2 leaf bit layout(encoder 存在;SC TEC bundle 内的逐 slot bit offset 未逐一解码)。
  • 每代 getVyEncodings window-map 内容。
  • Ghostlite/6acc60406 上的 Vmsk-index 字段宽度(推断约 4-bit)。
  • 6acc60406 (GF) 的 2-bit dual-predicate value 语义。

交叉引用