Viperfish 64 字节 Bundle
本页中的每个偏移、值和地址都从
libtpu-0.0.40-cp314wheel 中的libtpu.so按字节精确读取(BuildID md589edbbe81c5b328a958fe628a9f2207d,未 strip,包含完整 C++ 符号)。所有地址都是虚拟地址;.text和.rodata按 1:1 映射(VA == 文件偏移)。其他 wheel 版本会有所不同。
摘要
Viperfish(kViperfish,TpuVersion enum 3,外部称为 "TPU v5" / "TPU v5 lite")是第一个 VLIW issue word 宽度为 64 字节(512 bit)的 TPU TensorCore 世代,高于 Pufferfish 的 51 字节和 Jellyfish 的 41 字节。两个云端 SKU 名称都映射到这一个代号:accelerator-type 解析器 AcceleratorTypeToTpuVersionEnum(@ 0x204cf620)把 v5e 和 v5lite 路由到 enum case 5,把 v5p 路由到 case 6,但二者的 codec/HAL 家族都是单一的 Viperfish 世代,并不存在按云端名称区分的独立 codec。64 字节宽度不是通过对更窄的 bundle 做零扩展得到的,而是从 codec-metadata 虚函数 ViperfishCodecMetadata::BundleSizeBytes(TpuSequencerType)(@ 0x1ee71320,return 64)返回的(在 a2 == 0 组件检查之后),它是 Bundle Model 页面所述、以 (TpuVersion, TpuSequencerType) 为键的 codec-metadata 表中的一个单元。64 字节宽度也出现在后续两个 VXC 家族世代 Ghostlite(kGhostlite,enum 4,外部称为 "TPU v6 lite")和 6acc60406(k6acc60406,enum 5,外部称为 "TPU7x")中,但每个世代都有其自己的按世代区分的 codec 类和 slot-encoder 集;本页专门记录 Viperfish,并指出家族开始分化的位置。("Trillium" 没有出现在二进制中的任何位置;TPU7x 世代的内部名称是混淆标签 6acc60406。)
它与 JF/PF 模型的结构性断裂在于编码机制,而不只是宽度。Jellyfish 和 Pufferfish 各自都有一个单体 encoder,即 EncoderJf::EncodeBundleInternal(@ 0x1e86c7c0)和 EncoderPfTensorCore::EncodeBundleInternal(@ 0x1e8c5c40),它们遍历一个 Bundle 对象并内联打包每个 slot。Viperfish 没有 EncodeBundleInternal。它的顶层入口是 codec dispatcher TpuCodecViperfish::EncodeBundle(@ 0x1e8449a0),该函数按 TpuSequencerType 分派,并在 TensorCore 情况下(sequencer 0)构造 asic_sw::deepsea::vxc::isa::TensorCoreCodecBase<…>(其模板参数列表就是 slot-encoder 的遍历顺序),然后调用 viperfish::isa::EncoderVfTensorCore::EncodeBundle(@ 0x1d2f7ce0)。该函数把 bundle facade 转换为 vxc::isa::TensorCoreBundle(或 TensorCoreBundleCompact),分配一个长度为 BundleSizeBytes() 的清零缓冲区,然后调用 codec 的 TensorCoreBundle::Encode worker(vxc TensorCoreCodecBase 成员,位于 0x1d2f8… 范围),后者通过各自的 <Slot>Encoder::Encode 方法序列化每个 slot。每一次字段写入,即 opcode、operand、predicate,都经过一个通用的 bit 粒度 packer BitCopy(dst, dst_bit, src, src_bit, nbits)(@ 0x1fa0a900,LSB-first),因此整个 bundle layout 表示为一组扁平的 (absolute-bit, width) 三元组,而不是一次 struct cast。
注意 —
EncodeBundle @ 0x1e838cc0/TensorCoreCodecBaseworker0x1d371540(ctor0x1d371e80)处结构相似的 codec 不是 Viperfish:这些地址位于asic_sw::deepsea::gxc::gfc::isa(6acc60406 / gfc TPU7x codec,default分支tpu_codec_6acc60406.cc)。Viperfish 的逐 slot encoder 全部位于asic_sw::deepsea::vxc::isa;重建 vxc bundle 时不要交叉引用 gfc 地址。
本页其余部分映射这些三元组。它覆盖 slot 分类以及每个 slot 占用的字节,两个 MXU slot(VectorExtended0/1)及其 matmul / weight-latch / matpush / transpose / lane / cross-lane op 家族,用于 drain MXU 和 EUP 的 VectorResult0/1 pop slot,与其他所有 compute op 不同、位于 VALU slot 3 而不是专用 slot 的 EUP/transcendental push,immediate、sequencer 和 predicate slot 位置,以及 V5+ 在结构上如何不同于 JF/PF 的 EncodeBundleInternal 模型。
对重新实现而言,契约是:
- 64 字节宽度以及它是 codec-metadata 常量(
ViperfishCodecMetadata::BundleSizeBytes→64),通过(TpuVersion, TpuSequencerType)查找选择,绝不是通过扩展 51 字节 bundle 得到。 - V5+ 两阶段编码链:
isa_emitter::EmitX填充一个 proto submessage;随后<Slot>Encoder::Encode把每个 proto 字段BitCopy到 512-bit 缓冲区中按世代固定的绝对 bit。入口是TpuCodecViperfish::EncodeBundle→EncoderVfTensorCore::EncodeBundle;不存在EncodeBundleInternal。 - MXU slot 模型:两个
VectorExtendedslot(每个物理 MXU 一个)共享一个 8×6-bit systolic-feed vreg 区域,并拥有不同的 opcode/control 区域;matmul opcode 是 bit 57 处的 7-bit,data-format sub-discriminator 是 bit 51 处的 4-bit,MXU-id 是 bit 64 处的 4-bit。 - latch/push/matmul opcode 家族(
LoadMatrixRegister{Gmr,Lmr}{Msra,Msrb}、Pushmatrix<fmt>、MatrixMultiply<fmt>[Lgmr{Msra,Msrb}][Masked])以及 EUP push-pop 协议(VALU3 push →VectorResultPopEupResult)。
| 世代 | Viperfish — kViperfish,TpuVersion enum 3,外部称为 "TPU v5" / "TPU v5 lite"(参见 Bundle Model) |
| 云端 SKU | v5e/v5lite(case 5)和 v5p(case 6)位于 AcceleratorTypeToTpuVersionEnum @ 0x204cf620,二者都由同一个 Viperfish codec 服务 |
| 命名空间 | asic_sw::deepsea::vxc::isa (TC),asic_sw::deepsea::vxc::vfc::isa (SparseCore TEC/SCS) |
| Bundle 宽度 | 64 B / 512 bit — ViperfishCodecMetadata::BundleSizeBytes @ 0x1ee71320 return 64(在 a2==0 组件检查之后) |
| 宽度分派 | codec_metadata::BundleSizeBytes(TpuVersion, TpuSequencerType) @ 0x1ecf7180 → GetMetadataOrDie @ 0x1ecf6f60(CodecMetadataRegistry hash-map)→ vtable +16 |
| 编码入口 | TpuCodecViperfish::EncodeBundle @ 0x1e8449a0 → EncoderVfTensorCore::EncodeBundle @ 0x1d2f7ce0 → vxc TensorCoreCodecBase worker(0x1d2f8…),逐 slot Encoder::Encode 遍历 |
| 通用 packer | BitCopy(dst, dst_bit, src, src_bit, nbits) @ 0x1fa0a900 — bit 粒度,LSB-first(byte = dst_bit>>3,bit = dst_bit&7) |
| MXU slots | TensorCoreVectorExtended0Encoder::Encode @ 0x1efa0f60(按 proto opcode switch,最大 case 0x66=102 = CoreToCoreMove),…Extended1Encoder::Encode @ 0x1efec020 |
| Result slots | TensorCoreVectorResult0Encoder::Encode @ 0x1f018f40,…Result1Encoder::Encode @ 0x1f019d80 |
| EUP push | EncodeTensorCoreVectorAlu3EupPush @ 0x1ef6e400(VALU slot 3) |
| MXU op 统计 | 每个 slot 有 94 个 VectorExtended0 + 94 个 VectorExtended1 逐 op helper;0 个 Extended2/3Encoder(正好两个 MXU issue slot) |
| 置信度 | CONFIRMED(以字节锚定),除非某行另有说明 |
Slot 分类和字节映射
Viperfish bundle 是一个 512-bit 扁平缓冲区。每个功能单元读取其中一个连续的 bit window;这些 window 按世代固定,并由逐 slot encoder 填充。读者应当把 64 字节理解为一个从 bit 0 = byte 0 的 LSB 开始索引的 packed bitfield,与 BitCopy 的索引方式完全一致。
slot 分类与 Pufferfish 的 Bundle sub-instruction 集相同(参见 Bundle Model),但 V5+ 将 MXU 加倍,并把 EUP 移入 VALU。下表给出每个 slot、序列化它的 encoder,以及它占用的 bit 区域(来自代表性 op 中已验证的 BitCopy 偏移)。
| Slot | 引擎 | Encoder (asic_sw::deepsea::vxc::isa::…) | 区域 (bits) |
|---|---|---|---|
VectorExtended0 | MXU 0(matmul / latch / push / transpose / lane / xlane) | TensorCoreVectorExtended0Encoder::Encode @ 0x1efa0f60 | opcode/ctl ~48–64;operand pool 157–293 |
VectorExtended1 | MXU 1 | TensorCoreVectorExtended1Encoder::Encode @ 0x1efec020 | opcode/ctl ~28–44;共享 157–293 pool |
VectorResult0 | MXU/EUP/transpose result pop | TensorCoreVectorResult0Encoder::Encode @ 0x1f018f40 | 11–24(dest @ 14) |
VectorResult1 | 第二个 result pop | TensorCoreVectorResult1Encoder::Encode @ 0x1f019d80 | Result0 的镜像 |
VectorAlu0…3 | 4 条 VALU lane(Alu3 也发出 EUP push) | TensorCoreVectorAlu{0..3}Encoder::Encode | VALU0 opcode @ 299 w7;Alu3 EUP @ 186/197 |
VectorLoad0/1 | vector memory load | TensorCoreVectorLoad{0,1}Encoder | 按世代重新打包(参见 Memory Load) |
VectorStore | vector memory store | TensorCoreVectorStoreEncoder | data-vreg @ 170 w4;base @ 157 w6 |
ScalarAlu0/1 | sequencer / scalar pipe(branch/call/halt/LCC) | TensorCoreScalarAlu0Encoder::Encode @ 0x1eecb900 | opcode-low @ 488 w5;pred @ 499/503 |
Immediates | 6 个 immediate slot(branch/call offset 所在位置) | TensorCoreImmediatesEncoder::Encode @ 0x1eebee40 | imm0 @ 430 … imm5 @ 330,各 w20 |
Predicates | predicate pool(VF 上是逐 slot 字段) | slot 顶部的逐 slot 4+1 字段 | TC ScalarAlu0 @ 499/503 |
注意 — 字节区域并不是按 slot 以显而易见的方式连续排列。MXU operand pool(bits 157–293,八个 6-bit source vreg)物理上位于 bundle 中部,并在
VectorExtended0和VectorExtended1之间共享;只有每个 MXU slot 顶部的 opcode/control word 是不同的。如果重新实现假设每个 slot 都拥有一段私有连续字节,就会错误打包第二个 MXU。怪异点 — Viperfish TensorCore bundle 中没有
Sparsityslot。94 个VectorExtended0op 家族(matmul、latch、push、transpose、lane-broadcast/rotate、permute、cross-lane reduce、set-pattern-register、core-to-core move)不包含 structured-sparsity op。Structured sparsity 出现在后续世代;参见 Sparsity Slot(支撑性发现仍然开放,不要虚构 VF sparsity 字段)。
V5+ 编码模型 — 为什么没有 EncodeBundleInternal
目的
关于 Viperfish bundle 最重要的结构事实是它如何构建,因为 JF/PF 的心智模型在这里失效。Jellyfish 和 Pufferfish 带有逐 encoder 的 EncodeBundleInternal,它接收一个 Bundle,并在一个函数体内打包所有 slot,混合使用 and/shl/or(Jellyfish direct-pack)或 BitCopy(Pufferfish)。Viperfish 用模板化 codec 取代它,该 codec 的 slot 列表在编译时固定,并且每个 slot 有一个逐 slot encoder。寻找 EncoderVf::EncodeBundleInternal 的重新实现者不会找到它。
入口点
TpuCodecViperfish::EncodeBundle @0x1e8449a0 ── codec dispatch on TpuSequencerType (vxc)
├─ (TC, seq 0) → vxc::isa::TensorCoreCodecBase<…> ctor (operator new 0xF0)
│ EncoderVfTensorCore::EncodeBundle @0x1d2f7ce0
│ └─ TensorCoreBundle::Encode worker (0x1d2f8… range)
│ ── walks each slot Encoder in template-arg order:
│ ├─ TensorCoreImmediatesEncoder::Encode @0x1eebee40
│ ├─ TensorCoreScalarAlu0Encoder::Encode @0x1eecb900
│ ├─ TensorCoreVectorAlu{0..3}Encoder::Encode
│ ├─ TensorCoreVectorExtended0Encoder::Encode @0x1efa0f60 ── MXU 0
│ ├─ TensorCoreVectorExtended1Encoder::Encode @0x1efec020 ── MXU 1
│ ├─ TensorCoreVectorResult0Encoder::Encode @0x1f018f40
│ ├─ TensorCoreVectorResult1Encoder::Encode @0x1f019d80
│ ├─ TensorCoreVectorStoreEncoder::Encode
│ └─ TensorCoreVectorLoad{0,1,2}Encoder::Encode
├─ (SCS, seq 3) → vxc::vfc::isa::SparseCoreScsCodecBase<…> → EncoderVfSparseCoreScs::EncodeBundle
├─ (TAC, seq 4) → vxc::vfc::isa::SparseCoreTacCodecBase<…> → EncoderVfSparseCoreTac::EncodeBundle
└─ (TEC, seq 5) → vxc::vfc::isa::SparseCoreTecCodecBase<…> → EncoderVfSparseCoreTec::EncodeBundle
```text
> **注意 —** TC codec 模板列出了*三个* vector-load slot(`TensorCoreVectorLoad0/1/2`),并把 `Predication` 作为模板类型参数携带,而不是作为专用的 `TensorCorePredicatesEncoder` slot;该专用 predicate-slot encoder 首次出现在 6acc60406 (gfc) TC codec 中,这与 [Bundle Model](bundle-model-overview.md) 关于 predicate slot 是 6acc60406 新增项的说明一致。
### 算法
两阶段链是:上游 `isa_emitter` EmitX 模板填充 proto submessage 并设置其 present bit;下游 slot encoder 读取该 submessage,并把每个字段 `BitCopy` 到它的绝对 bit。encoder 函数体把逐 op 打包内联为对 proto opcode(proto + 0x50)的 `switch`;每个 `switch` 分支都是一个 op 家族的字段 layout。
```c
function TpuCodecViperfish::EncodeBundle(out, bundle, seq): // @0x1e8449a0
switch (seq): // TpuSequencerType
case 0: codec = vxc::TensorCoreCodecBase<…>() // TC
EncoderVfTensorCore::EncodeBundle(out, bundle) // @0x1d2f7ce0
case 3: …SparseCoreScs… case 4: …SparseCoreTac… case 5: …SparseCoreTec…
function EncoderVfTensorCore::EncodeBundle(out, bundle): // @0x1d2f7ce0
tc = cast<vxc::isa::TensorCoreBundle>(bundle) // or TensorCoreBundleCompact
buf = zeroed(tc.BundleSizeBytes()) // 64 bytes
tc.Encode(buf) // vxc TensorCoreCodecBase worker, walks slot encoders
// worker, in template-arg order, calls each SlotEncoder.Encode(slot_proto, buf):
function TensorCoreVectorExtended0Encoder::Encode(proto, out): // @0x1efa0f60
out_field = *(int*)(proto + 0x1c)
BitCopy(out, 64, &out_field, 0, 4) // MXU-id (unit) written FIRST, always
switch (*(int*)(proto + 0x50)): // proto opcode — the op-family dispatch
case 0: return // empty slot — nothing packed
case 0xC: EncodeMatrixMultiplyBf16(out, proto) // = decimal 12
case 0x41: EncodePushmatrixBf16(out, proto) // = decimal 65
case …: // 94 op families; max case 0x66 (=102) = CoreToCoreMove陷阱 — present-bit guard。每个字段的
BitCopy都受 proto present bit((proto[2] & mask) != 0)保护,字段缺失时 encoder 会读取一个默认实例全局对象(…_globals_),而不是跳过。反编译出的MatrixMultiplyBf16函数体(@0x1efa2e40)对每个字段都交织了 live-proto 路径和…MatrixMultiplyBf16_globals_默认路径。如果重新实现省略默认实例 fallback,就会在字段未设置时留下陈旧 bit;未设置 matmul source vreg 的硬件默认值是 proto 默认值携带的内容,而不是零。
MXU Slots — VectorExtended0 / VectorExtended1
目的
每个 VectorExtended slot 驱动一个 MXU,并携带完整的 matrix-unit op 词汇表:dense matmul(MatrixMultiply<fmt>)、weight-stationary latch(LoadMatrixRegister{Gmr,Lmr}{Msra,Msrb})、moving-operand push(Pushmatrix<fmt>)、latch-via-LMR fused matmul(MatrixMultiplyLmr / …Lgmr{Msra,Msrb}),以及 transpose、lane-broadcast/rotate、permute、cross-lane reduce 和 pattern-register op。正好有两个 slot:二进制中有 94 个 Extended0 和 94 个 Extended1 逐 op helper,并且 没有 Extended2/3。
编码 — 绝对 Bit 映射
Viperfish 的 MXU control 区域已从反编译的 MatrixMultiplyBf16(@ 0x1efa2e40)、PushmatrixBf16(@ 0x1efaf820)和 LoadMatrixRegisterGmrMsra helper 中验证:
| 字段 | 绝对 bit | 宽度 | 写入者 | 值(Bf16 情况) |
|---|---|---|---|---|
| MXU-id (unit) | 64 | 4 | dispatcher (proto + 0x1c) | 0 (MXU 0) |
| opcode-HIGH (matmul) | 57 | 7 | MatrixMultiply<fmt> | 0x1 |
| opcode-HIGH (latch) | 57 | 7 | LoadMatrixRegister* | 0x37 (55) |
| opcode-HIGH (push) | 59 | 5 | Pushmatrix<fmt> | 0xe (14) |
| data-format sub-disc | 51 | 4 | 逐 op | matmul Bf16=1 / push Bf16=3 / latch=0 |
| control (3-bit) | 48 | 3 | 逐 op | proto + 0x18 |
| done-gains / latch flag | 55 | 2 | 逐 op | proto + 0x1c |
| Transpose field (push/latch) | 57 | 1 | Pushmatrix* (proto + 0x20) | — |
| Target field (push/latch) | 58 | 1 | Pushmatrix* (proto + 0x24) | — |
| push-src vreg | 180 | 6 | Pushmatrix* (proto + 0x44) | — |
| primary operand (matmul) | 180 | 6 | MatrixMultiply* | proto + 0x3c |
| src vreg #1 (proto + 0x20) | 157 | 6 | matmul | systolic feed |
| src vreg #2 (proto + 0x24) | 282 | 6 | matmul | systolic feed |
| src vreg #3 (proto + 0x28) | 293 | 6 | matmul | systolic feed |
| src vreg #4 (proto + 0x2c) | 248 | 6 | matmul | systolic feed |
| src vreg #5 (proto + 0x30) | 259 | 6 | matmul | systolic feed |
| src vreg #6 (proto + 0x34) | 214 | 6 | matmul | systolic feed |
| src vreg #7 (proto + 0x38) | 225 | 6 | matmul | systolic feed |
怪异点 — opcode 字段在同一个 slot 中会随 op 家族同时改变位置和宽度。
MatrixMultiply<fmt>在 bit 57 写入 7-bit opcode;Pushmatrix<fmt>在 bit 59 写入 5-bit opcode-HIGH(下方 bit 51 是 4-bit data-format);LoadMatrixRegister*复用 @ 57 的 7-bit window,但值为0x37。在 push 路径上,bits 57 和 58 被重新用途化为 1-bit Transpose 和 Target 字段,也就是 matmul 路径上 7-bit opcode 的两个高位所在的相同物理 bit。decoder 通过 opcode-HIGH 值区分它们(push/latch 的 opcode-HIGH 是0xe,matmul 是0x1),因此 LSB 区域可以自由承载 latch control。在 decode 侧,Pushmatrix*TransposeField读取[base+8]>>0x39&1= abs57,…TargetField读取>>0x3a&1= abs58。
共享 Systolic-Feed Operand Pool
八个 source-vreg 字段(bits 157/282/293/248/259/214/225 加上 operand @ 180)是进入 MXU 的 systolic operand stream。决定性的结构事实是:VectorExtended0 和 VectorExtended1 从相同的绝对 bit读取相同的 vreg,只有 opcode/control 区域在两个 slot 之间不同。两个 MXU 从同一组 vector read port 取数;两个 slot 通过一个共享 operand pool 寻址两个物理 matrix unit。
// VectorExtended0 (MXU 0) and VectorExtended1 (MXU 1):
// opcode/control region: distinct per slot (Extended1 shifted down ~20 bits)
// operand pool 157..293: IDENTICAL absolute bits in both slots
function EncodeMatrixMultiplyBf16(out, proto): // @0x1efa2e40, proto opcode 0xc
BitCopy(out, 57, {0x1}, 0, 7) // opcode-HIGH = 1
BitCopy(out, 51, {0x1}, 0, 4) // data-format = bf16
BitCopy(out, 48, proto.control, 0, 3)
BitCopy(out, 55, proto.done_gains, 0, 2)
BitCopy(out, 157, proto.src0, 0, 6) // present-gated; else read globals_
BitCopy(out, 282, proto.src1, 0, 6)
BitCopy(out, 293, proto.src2, 0, 6)
BitCopy(out, 248, proto.src3, 0, 6)
BitCopy(out, 259, proto.src4, 0, 6)
BitCopy(out, 214, proto.src5, 0, 6)
BitCopy(out, 225, proto.src6, 0, 6)
BitCopy(out, 180, proto.operand, 0, 6)
```text
### Op 清单
每个 slot 的 94 个 helper 并不是 94 种不同 layout,而是一个 `{opcode, sub-format, MXU-id, operand}` 模板,按 opcode immediate 和 operand-present mask 特化。op 家族如下:
| 家族 | 成员 | 作用 |
|---|---|---|
| `MatrixMultiply<fmt>` | Bf16, Bf8, If8Bf16, S4, S8, U4, U8, F32Rounded, Lmr | dense matmul step,每个数据格式一个 helper |
| `MatrixMultiply<fmt>Lgmr{Msra,Msrb}[Masked]` | 每种 fmt × {Msra, Msrb} × {plain, Masked} | latch-via-LMR fused matmul(多 pass K-tiling) |
| `Pushmatrix<fmt>` | Bf16, Bf8, S4, S8, U4, U8, Rounded, PackedIf8Conv | moving-operand push(matprep) |
| `LoadMatrixRegister{Gmr,Lmr}{Msra,Msrb}` | 4 个变体 | weight-stationary latch(opcode-HIGH `0x37`) |
| `*TransposeStart[End]`, `*TransposeContinueAnyType`, `Segmented*`, `Packed*` | ~10 | systolic-array transpose |
| `LaneBroadcast[Packed]`, `LaneRotate`, `PackedLaneRotate`, `Permute[Packed]` | ~6 | lane 内数据移动 |
| `Xlane{Add,Max,Min}[Index]` | 5 | cross-lane reduction |
| `SetPatternRegisterPcr[Bytes,Sublanes]`, `CoreToCoreMove`, `SupplementalPackedXlu` | 4 | pattern-register / inter-core / XLU supplement |
> **注意 —** `Masked` 后缀和 `Lgmr{Msra,Msrb}` 后缀是 Jellyfish 6 项 `GainLatchMode → VEOpcode` 表在 V5+ 上的实现:v3 上的小 enum 在 v5 上变成了具名 opcode 家族。`Msra`/`Msrb` 选择 fused matmul 累积进入两个 matrix-staging-register bank 中的哪一个。跨世代 opcode 故事参见 [MXU Slot](slot-mxu.md),各项延迟参见 [MXU Latency (Viperfish)](../cost/mxu-latency-vf.md)。
---
## Result Slots — VectorResult0 / VectorResult1
### 目的
`VectorResult` slot 是 push-pop 协议的 *pop* 侧。它 drain 已完成的 MXU matmul(`PopMxuResult`)、EUP transcendental result(`PopEupResult`)、transpose result(`TransposeResult`),或者 Viperfish 独有的 scalar/CRF pop(`PopCcrfResult`)。该 slot 是一个 discriminator-plus-tail layout:4-bit result-type discriminator 选择存在的 sub-message,common tail `BitCopy` dest vreg。
### 编码 — 绝对 Bit 映射(Viperfish)
已从 `TensorCoreVectorResult0Encoder::Encode`(@ `0x1f018f40`)验证:
| 字段 | 绝对 bit | 宽度 | 说明 |
|---|---|---|---|
| header field (proto + 0x1c) | 24 | 4 | 每种 result-type 都最先写入 |
| sub-type selector | 22 | 2 | 常量 0/1/2/3 = PopEup / PopMxu / Transpose / PopCcrf |
| result mode (proto + 0x18) | 20 | 2 | 逐 result-type(仅 Mxu/Transpose) |
| dest vreg | 14 | 6 | common tail |
四个 Viperfish sub-message(位于 `asic_sw::deepsea::vxc::isa` 下的 proto 类型)由 `proto + 0x50` opcode 分派,并由 bit 22 处的 2-bit selector 标记:
| Sub-message | proto opcode | bit-22 selector | 作用 |
|---|---|---|---|
| `TensorCoreVectorResult_PopEupResult` | 5 | 0 | drain 一个 EUP/transcendental result |
| `TensorCoreVectorResult_PopMxuResult` | 6 | 1 | drain 一个已完成的 MXU matmul accumulator |
| `TensorCoreVectorResult_TransposeResult` | 7 | 2 | drain 一个 systolic transpose |
| `TensorCoreVectorResult_PopCcrfResult` | 8 | 3 | scalar/cross-core-register-file pop(仅 vxc) |
> **陷阱 —** bit 22 处的 2-bit selector(值 0/1/2/3)是 decoder 用来判别的字段,并且它**不**等于 `proto + 0x50` opcode(5/6/7/8)。encoder 读取 opcode 来选择 `switch` 分支,然后写入*selector* 常量。PopEup 可从两个分支到达:opcode 5 和 opcode 8(PopCcrf 分支的 `else` 会落入 PopEup 默认实例),因此把 opcode→selector 做 1:1 映射的重新实现会错误标记。无论 sub-type 如何,dest vreg 都落在 common tail bit 14(w6)。
>
> **怪异点 —** result sub-message *集合* 是按世代变化的,不是常量:跨世代重新实现必须按 `TpuVersion` 判别它,而不能假设 Viperfish 的四项会延续。在 Viperfish 上集合是 `{PopEup, PopMxu, Transpose, PopCcrf}`(上述四个 `switch` 分支)。Ghostlite 和 6acc60406 的集合不同(例如 Ghostlite 为 K>128 multi-pass 路径增加了 fused matres+accumulate result);这些差异记录在各世代 bundle 页面中。
---
## EUP / Transcendental Push — VALU Slot 3
### 目的
Extended Unary Processor(transcendental unit)没有专用 bundle slot。它的 **push** 是 VALU slot-3(`Alu3`)op,而它的 **pop** 是 `VectorResult` `PopEupResult`。这是 push-pop transcendental 模型的 bit 精确实现:一个 `Alu3` op 把 source vreg 推入 EUP pipeline,并携带 5-bit function selector;一个或多个 bundle 之后,`VectorResult` op 把结果 pop 到 dest vreg。单 issue EUP 意味着只有 `Alu3`(而不是 `Alu0/1/2`)作为 push 来源;transcendental helper 只存在于 `Alu3` 集合中。
### 编码 — 绝对 Bit 映射(Viperfish)
已从 `EncodeTensorCoreVectorAlu3EupPush`(@ `0x1ef6e400`)验证:
| 字段 | 绝对 bit | 宽度 | 值 |
|---|---|---|---|
| VALU opcode (EUP-push family) | 197 | 7 | `0x0` |
| EUP-function selector | 186 | 5 | 泛型 `EupPush` 为 `0x16` (22) |
| src vreg | 191 | 6 | proto + 0x18(present-gated) |
```c
function EncodeTensorCoreVectorAlu3EupPush(out, proto): // @0x1ef6e400
BitCopy(out, 197, {0x0}, 0, 7) // VALU-opcode = EUP-push family
BitCopy(out, 186, {0x16}, 0, 5) // generic EUP-push function selector = 22
if (proto[0x50] == 135 && present): // proto opcode 135 = EupPush
BitCopy(out, 191, proto.src, 0, 6)Push-Pop 协议
bundle N : VALU slot 3 (Alu3) ── VALU-op=0x0 @197, fn-selector @186, src vreg @191
│
▼ (EUP pipeline latency; single-issue XLU hazard)
bundle N+k : VectorResult slot ── PopEupResult (result-opcode 7), dest vreg @14
```text
> **注意 —** Viperfish 的具名 transcendental(`Reciprocal`、`ReciprocalSqrt`、`Tanh`、`ShiftedSigmoid`、`LogTwo`、`PowTwo`)各自都有自己的 `Alu3` helper,在相同的 bit-186 字段中携带自己的 5-bit selector;上方的 `0x16` 值是*泛型* `EupPush`,其函数携带在别处。逐函数 selector 值表(Tanh、Reciprocal、Erf、Sin/Cos 等)按世代记录在 [EUP Transcendental Slot](slot-eup-transcendental.md)。pop dest vreg 落在公共 `VectorResult` tail(bit 14 w6),因此 transcendental result 在 push 之后一个或多个 bundle 中占用普通 vreg。
---
## Sequencer、Immediate 和 Predicate 位置
这些 slot 并非 MXU 专属,但固定了 512-bit 映射的其余部分。它们来自同一个 `<Slot>Encoder::Encode` + `BitCopy` 机制,完整记录在 [V5+ EmitX Bit Positions](v5plus-emitx-bit-positions.md);这里为完整性汇总 Viperfish 位置。
### Immediate slots — branch/call/sync offset 所在位置
`TensorCoreImmediatesEncoder::Encode`(@ `0x1eebee40`)写入六个 20-bit immediate slot,分别来自 `proto + 0x18 … 0x2c`。branch/call/sync 的 20-bit signed offset 落在 **immediate slot 0**:
| imm slot | proto field | VF 绝对 bit | 宽度 |
|---|---|---|---|
| 0 (branch/call offset) | proto + 0x18 | 430 | 20 |
| 1 | proto + 0x1c | 410 | 20 |
| 2 | proto + 0x20 | 390 | 20 |
| 3 | proto + 0x24 | 370 | 20 |
| 4 | proto + 0x28 | 350 | 20 |
| 5 | proto + 0x2c | 330 | 20 |
### Sequencer slot
`TensorCoreScalarAlu0Encoder::Encode`(@ `0x1eecb900`)写入公共 predication header,然后按 proto opcode 分派。control-op layout:
| 字段 | 绝对 bit | 宽度 | 说明 |
|---|---|---|---|
| predication reg index | 499 | 4 | proto + 0x20 |
| predication inversion | 503 | 1 | proto + 0x18 (byte) |
| opcode-HIGH / family | 493 | 6 | branch/call 为 0 |
| opcode-LOW / discriminator | 488 | 5 | 4/5/6/7 |
| x-target sreg (`BranchSreg`) | 488 | 5 | sreg `x()` |
| dest (return-addr) sreg | 477 | 5 | `Call` dest |
Discriminator:`BranchAbsolute=4`、`BranchRelative=5`、`CallAbsolute=6`、`CallRelative=7`。branch offset 是 immediate slot 0(bit 430)中的 signed 20-bit 值;没有专用 return op,return 是读取 link sreg 的 `BranchSreg`。
> **陷阱 —** Viperfish 中没有 in-bundle delay-slot 字段。branch/call helper 只写入 `{opcode-low, offset (imm0), dest}`;delay-slot 计数是 bundle-packer pad-count(branch 后追加的空 `kNeverExecute` bundle),不是已编码的 bit 字段。寻找 3-bit `delay_slots` 字段的重新实现不会找到它。
### Predicate slot
Viperfish 在每个 scalar slot 顶部使用**逐 slot** 4+1 predicate 字段(4-bit reg index + 1-bit inversion);对 `TensorCoreScalarAlu0` 而言,reg 位于 bit 499(w4),inversion 位于 bit 503(w1)。`Predication` 是 vxc TC codec 的模板类型参数,而不是 standalone slot encoder。这是后续 6acc60406(TPU7x)世代用专用 `TensorCorePredicatesEncoder` slot 替换的编码方式;在 Viperfish 上,predicate index 局部于每个已填充 slot。空 slot 携带写入 bundle header 的 `kNeverExecute` predicate(参见 [Bundle Model](bundle-model-overview.md))。
---
## Viperfish 与 JF/PF Bundle 模型的差异
| 轴 | Jellyfish (41 B) / Pufferfish (51 B) | Viperfish (64 B) |
|---|---|---|
| 编码入口 | 一个 `Encoder<gen>::EncodeBundleInternal` 打包所有 slot | `TpuCodecViperfish::EncodeBundle` → `EncoderVfTensorCore::EncodeBundle` → 逐 slot `<Slot>Encoder::Encode` |
| 字段写入 | JF 直接 `and`/`shl`/`or`;PF `BitCopy` | 每个字段都经由 `BitCopy`;没有 direct-pack |
| Layout 来源 | `Bundle` 上的逐 slot `Encode` 方法 | `isa_emitter::EmitX` proto 模板 + slot encoder |
| InstBits 表 | (n/a) | InstBits 在磁盘上全为零;位置存在于 encoder 中 |
| MXU slots | JF 1 个 `VectorExtended`;PF 2 个(`VE0/1`) | 2 个(`VectorExtended0/1`),各 94 个 helper,0 个 `Extended2/3` |
| MXU operand 模型 | JF 单个 moving-operand vreg | 8×6-bit systolic-feed pool,在两个 MXU slot 间*共享* |
| Latch 编码 | JF 6 项 `GainLatchMode→VEOpcode` 表 | 具名 `LoadMatrixRegister{Gmr,Lmr}{Msra,Msrb}` opcode 家族(opcode-HIGH `0x37`) |
| EUP transcendental | 从 VALU slot issue,由 result slot pop | 固定到 VALU **slot 3**(`Alu3`);5-bit fn-selector @ bit 186 |
| Bundle 宽度来源 | encoder 中的内联常量 | `ViperfishCodecMetadata::BundleSizeBytes` → `64`(codec-metadata cell) |
简洁地表述这个断裂:Pufferfish 的 `EncodeBundleInternal` *就是*其 slot 的 kIsaTable,烘焙在一个函数里。Viperfish 没有这样的函数;它的 kIsaTable 是分布在约 200 个逐 op helper 中的一*组*逐 slot `BitCopy` 偏移,由 `TpuCodecViperfish::EncodeBundle` → `EncoderVfTensorCore::EncodeBundle` 编排。LLVM-MC 通常用来保存固定 instruction bits 的 InstBits 表,在所有 V5+ 世代的磁盘内容中全为零,这从二进制层面确认这些 bit 来自 emitter path,而不是静态表。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| Pufferfish 51B Bundle | 直接前代:单体 `EncodeBundleInternal`,2 个 MXU slot,没有 shared-pool / VALU3-EUP 模型 |
| Ghostlite / 6acc60406 | 另外两个 64 字节 VXC 家族世代(外部称为 "TPU v6 lite" / "TPU7x");相同 slot grid,opcode/predicate 区域按字节平移,result sub-message 集不同 |
| Bundle Model | 跨世代 width-dispatch 和 slot-taxonomy 参考 |
| MXU Slot | 本页为 VF 专门化的跨世代 matmul/latch opcode 故事 |
## 交叉引用
- [Pufferfish 51B Bundle](bundle-pf-51b.md) — 前代;Viperfish 替换掉的 `EncodeBundleInternal` 模型
- [Ghostlite Bundle](bundle-gl.md) — 同族 64 字节世代;`PopAddMxu01Result`,按字节平移的 opcode 区域
- [Bundle Model](bundle-model-overview.md) — bundle 宽度、codec-metadata 分派、`kNeverExecute` 空 slot 约定
- [V5+ EmitX Bit Positions](v5plus-emitx-bit-positions.md) — `isa_emitter::EmitX` → `BitCopy` 链以及完整的 sequencer/immediate/predicate 位置
- [Sparsity Slot](slot-sparsity-v5plus.md) — structured-sparsity slot(开放;Viperfish TC bundle 中不存在)
- [MXU Slot](slot-mxu.md) — 跨世代 matmul/latch/push opcode 家族
- [EUP Transcendental Slot](slot-eup-transcendental.md) — 逐函数 EUP selector 值表和 pop 语义
- [IsaEmitter Registry](isa-emitter-registry.md) — 选择 Viperfish encoder 的 `(TpuVersion, SequencerType)` codec cell 统计
- [MXU Latency (Viperfish)](../cost/mxu-latency-vf.md) — Viperfish matmul/latch 家族的逐 op MXU cost