Dragonfish 包
地址适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so。其他版本会有所不同。
摘要
Dragonfish (TpuVersion::kDragonfish = 1) 没有自己的包布局。它的 TensorCore VLIW 包就是完全相同的 41 字节(328 位)Jellyfish 包:相同的 internal-struct/12-byte-strip 机制、相同的 slot-mask 分发、相同的逐槽位 bit 位置、相同的 kNeverExecute 预填充。共享布局并不是从宽度巧合推断出来的;它在二进制中具有结构性证据。EncoderDf 是 EncoderJf 的 C++ 子类,只覆盖三个槽位写入器,并且没有提供 EncodeBundleInternal、没有提供 BundleSizeBytes、也没有提供 DragonfishCodecMetadata:包组装器、宽度常量和编解码元数据类都从 Jellyfish 继承。Dragonfish 和 Jellyfish 在选择 codec 的所有位置都成对出现:encoder factory 为版本 0+1 构建一个共享的 CreateEncoderJfDf,Dragonfish 也复用 JellyfishBundleRestrictions,而不是携带自己的限制类。
唯一的 Dragonfish 专属行为,是叠加在继承的 Jellyfish encoder 之上的一组 MXU 有效性检查。EncoderDf 恰好覆盖三个命名 MXU 的槽位写入器:EncodeVectorExtendedInstruction、EncodeVectorResultInstruction 和 EncodeMiscInstruction。每个覆盖版本都会逐字调用 Jellyfish encoder,然后运行 CheckMxuValid<T> 来拒绝任何 mxu_num >= 2 的 op。这些检查不写入任何包 bit;它们只是纯合法性门控,外加位于 this+12 的内部 encoder 状态标志,用来反映 Dragonfish 不同的物理 MXU 配置。线缆格式逐字节等同于 Jellyfish 41 字节包。
因此,本页有意保持简短:它记录共享 codec 的证据和精确的 Dragonfish 差异,并把完整槽位图交给规范的 Jellyfish 页面。对重新实现而言,契约是:
- Dragonfish 编码的同一个 41 字节包与 Jellyfish 相同:逐字复用 Jellyfish 41B 包 槽位图。
EncoderDf继承EncodeBundleInternal、BundleSizeBytes和JellyfishCodecMetadata;不要实现单独的 Dragonfish codec。- 唯一的 Dragonfish 专属代码是
CheckMxuValid<T>,它在三个携带 MXU 的槽位 encoder 中拒绝mxu_num >= 2:这是有效性差异,而不是布局差异。
| Encoder 类 | EncoderDf(EncoderJf 的子类);ctor 0x1e85e340 调用 EncoderJf::EncoderJf(this, 1) |
| 包组装器 | 继承的 EncoderJf::EncodeBundleInternal @ 0x1e86c7c0(没有 EncoderDf 覆盖) |
| 线缆宽度 | 41 字节 / 328 位:继承的 JellyfishCodecMetadata::BundleSizeBytes @ 0x1ecf7460 |
| Codec 元数据 | 共享 JellyfishCodecMetadata;不存在 DragonfishCodecMetadata 符号 |
| Encoder factory | CreateEncoderJfDf 服务版本 0(Jellyfish)+ 1(Dragonfish) |
| 包限制 | 共享 JellyfishBundleRestrictions(没有 Dragonfish 专属类) |
| Dragonfish 差异 | CheckMxuValid<T>(mxu_num < 2)位于 EncodeVectorExtended/Result/MiscInstruction |
共享 Codec 的证据
四项相互独立的二进制证据表明,Dragonfish 复用 Jellyfish 41 字节包 codec,而不是携带自己的 codec。
1 — EncoderDf 是 EncoderJf 的子类。 Dragonfish encoder 构造函数先构造一个 EncoderJf 基类,然后安装自己的 vtable:
// EncoderDf::EncoderDf() @ 0x1e85e340 (decompiled)
EncoderJf::EncoderJf(this, 1); // construct the Jellyfish base (config arg = 1)
*(void**)this = off_21D36BF0; // install the EncoderDf vtable
// vmovaps/vmovups: store a 16-byte config blob at this+0x40
*((uint32*)this + 20) = 4; // set the per-gen config word
```text
`EncoderJf::EncoderJf(this, 1)` 调用就是字面意义上的 IS-A:Dragonfish encoder *就是*带有不同 vtable 和 config word 的 Jellyfish encoder。`EncoderDf` 没有覆盖的每个 Jellyfish 方法都会分发到 Jellyfish 实现。
**2 — `EncoderDf` 没有 `EncodeBundleInternal`,也没有 `BundleSizeBytes`。** 符号表扫描能找到一个 `EncoderJf::EncodeBundleInternal`(`0x1e86c7c0`)和一个 `EncoderBcsDf::EncodeBundleInternal`(`0x1e85cd20`,这是 *BarnaCore-sequencer* encoder,属于不同 sequencer 类型),但**没有 `EncoderDf::EncodeBundleInternal`**,也**没有 `EncoderDf::BundleSizeBytes`**。包组装器和宽度常量原样从 Jellyfish 继承。
**3 — 不存在 `DragonfishCodecMetadata`。** Codec 元数据类包括 `JellyfishCodecMetadata`、`PufferfishCodecMetadata`、`ViperfishCodecMetadata`、`GhostliteCodecMetadata`,没有 Dragonfish 条目。Dragonfish 的宽度来自同一个 `JellyfishCodecMetadata::BundleSizeBytes`(`0x1ecf7460`),它为 TensorCore(component 0)返回 41,为 BarnaCore(component 1)返回 16。[包模型](bundle-model-overview.md) 正是基于这一原因把 Dragonfish 列为共享 Jellyfish codec 元数据。
**4 — factory 和包限制把 0+1 成对处理。** Encoder factory 把版本 0 和 1 路由到一个共享的 `CreateEncoderJfDf`,Dragonfish 也复用 `JellyfishBundleRestrictions`,而不是 Dragonfish 专属类。这种配对是共享 codec 的直接二进制证据:参见 [代号矩阵](../targets/tpu-version-codename-matrix.md) 和 [JXC 家族](../targets/jxc-family.md) 页面,其中一个 `TpuHalJxcHardwareFactory` 和一个共享的编译器侧 `xla::jellyfish::isa` 命名空间服务两代硬件。
> **注 — `TpuCodecDragonfish` 存在,但它不是单独的*包* codec。** `TpuCodec::Create` 有一个 case 1,会构建名为 `TpuCodecDragonfish` 的对象(`CreateTpuCodecDragonfish` @ `0x1e8360e0`),并且 `TpuCodecDragonfish::EncodeBundle`(`0x1e8369a0`)存在。但这个 wrapper 自身不做 bit-packing:它对 `TpuSequencerType` 执行 `switch`,并把 TensorCore sequencer(type 0)转发给 `EncodeSequencerBundle<EncoderDf>`,把 BarnaCore sequencer(type 1)转发给 `EncodeSequencerBundle<EncoderBcsDf>`,把地址处理器(type 2)转发给 `EncodeBarnaCoreAddressHandlerBundle<EncoderJf>`;sequencer type 3–5 返回 `Unimplemented`。因此 TensorCore 路径落到 `EncoderDf`,其 `EncodeBundleInternal` 是继承来的 `EncoderJf` 版本:这个具名 codec 是分发/RTTI wrapper,而不是独立的 41 字节布局。重新实现时应为两代建模一个 41 字节包 codec,由 `TpuVersion` 参数分发,而不是建两个。
---
## Dragonfish 差异:MXU 有效性检查
`EncoderDf` 恰好覆盖三个槽位写入器,也就是引用 MXU 的三个写入器。每个覆盖版本都遵循同一形状:逐字调用 Jellyfish encoder(它会写入所有包 bit),然后对槽位的 `mxu_num` 运行 `CheckMxuValid<T>`,最后更新一个内部 encoder 状态标志。没有任何覆盖版本会触碰包的字节位置。
```c
// EncoderDf::EncodeVectorExtendedInstruction @ 0x1e85e520 (decompiled, representative)
status = EncoderJf::EncodeVectorExtendedInstruction(this, inst, bundle); // identical bit layout
if (!status.ok()) return status; // encoder_df.cc:65
if (!CheckMxuValid<VectorExtendedInstruction>(inst, inst->mxu_num).ok()) // mxu_num < 2 gate
return status; // encoder_df.cc:66
if (inst->mxu_num == 1 && (this->state[+12] & 0x600000000) == 0)
this->state[+12] |= 2; // internal MXU-1 tracking flag
return ok;CheckMxuValid<T> 是纯合法性门控:它永远不会写入包:
// EncoderDf::CheckMxuValid<T>(inst, mxu_num)
// <VectorExtendedInstruction> @ 0x1e85e5c0
// <VectorResultInstruction> @ 0x1e85e420
// <MiscInstruction> @ 0x1e85e7a0
function CheckMxuValid(inst, mxu_num):
if mxu_num >= 2:
return InvalidArgument("invalid mxu_num for " + inst.ShortDebugString()); // encoder_df.cc:36
return ok;
```text
`CheckMxuValid` 是一个函数模板,针对每种槽位类型实例化一次;三个实例化版本共享完全相同的函数体(`mxu_num >= 2` → `MakeErrorImpl<3>`,位置 `encoder_df.cc:36`,消息 `"invalid mxu_num for " + ShortDebugString`)。
三个覆盖版本以及它们验证 `mxu_num` 的槽位:
| 槽位 encoder(`EncoderDf`) | 地址 | 验证其 `mxu_num` 的对象 | 委托给(JF 基类) | `CheckMxuValid<T>` |
|---|---|---|---|---|
| `EncodeVectorExtendedInstruction` | `0x1e85e520` | vector-extended / matmul / latch op(`inst+0x70`) | `EncoderJf::EncodeVectorExtendedInstruction` @ `0x1e869f00` | `0x1e85e5c0` |
| `EncodeVectorResultInstruction` | `0x1e85e380` | matres / result-FIFO op(`inst+0x4C`) | `EncoderJf::EncodeVectorResultInstruction` @ `0x1e865ae0` | `0x1e85e420` |
| `EncodeMiscInstruction` | `0x1e85e6c0` | misc op 的 MXU 操作数:`ClearResultFifoOperands` 子消息(或其 `_globals_` 默认值),`mxu_num` 位于子消息 `+0x1C` | `EncoderJf::EncodeMiscInstruction` @ `0x1e86be80` | `0x1e85e7a0` |
这些正是命名 MXU 的三个槽位。vector-ALU、scalar、vector-load 和 vector-store 槽位完全没有 `EncoderDf` 覆盖:它们由继承的 Jellyfish 写入器编码,不执行任何 Dragonfish 专属检查,因为它们不寻址矩阵单元。
> **特性 — Dragonfish 差异是*有效性*差异,而不是*布局*差异。** 重新实现者必须用 Jellyfish 槽位图编码 Dragonfish 包字节:相同的 **LSB-first** bit 编号、相同的逐槽位 `shl`/`or` shift 常量(见 [Jellyfish 41B 包](bundle-jf-41b.md) 和 [包模型](bundle-model-overview.md#what-a-bundle-is));bit 位置逐字节相同。同时还要拒绝任何命名 `mxu_num >= 2` 的 matmul / matres / misc op。该检查改变的是*哪些程序可以编码*,而不是*bit 落在哪里*。跳过检查会为越界 MXU 产生 bit 相同但非法的包;在没有布局差异的位置添加布局差异会破坏每个 Dragonfish 包。
内部 `this+12` 状态更新是 encoder 记账:它跟踪一个包已经提交到哪个 MXU,防止同一包中的后续槽位声明冲突的 MXU。三个覆盖版本各自对同一个 `this+12` qword 使用不同 mask:vector-extended 覆盖版本测试 `& 0x600000000` 并设置 `| 2`(反编译显示 `mxu_num == 1` 分支),`EncodeVectorResultInstruction` 测试 `& 0x300000 == 0x100000` 并设置 `| 0x300000`,`EncodeMiscInstruction` 清除低 5 bit 字段,并在其 `ClearResultFifoOperands` 形式下有条件地设置 `| 0x60`。这个状态存在于 encoder 对象中,而不是包 word 中,在线缆上不可见。
---
## 交叉引用
- [Jellyfish 41B 包](bundle-jf-41b.md):Dragonfish 逐字复用的规范 41 字节槽位图、预填充和 packing 模型。
- [代号矩阵](../targets/tpu-version-codename-matrix.md):`kDragonfish = 1`、其代号字符串,以及 0+1 共享 encoder 配对。
- [JXC 家族](../targets/jxc-family.md):服务 Jellyfish 和 Dragonfish 两代的单一 HAL 家族以及 `xla::jellyfish::isa` 命名空间。