VXC 家族 (Viperfish)
地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id
89edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。
摘要
VXC 是四个 HAL 家族中覆盖面最广的一个。工厂类 tpu::TpuHalVxcHardwareFactory 独特地位于全局命名空间,而 JXC 和 PXC 位于匿名命名空间;它服务三个代号:Viperfish (TpuVersion::kViperfish = 3)、Ghostlite (kGhostlite = 4) 和 6acc60406 (k6acc60406 = 5)。Viperfish 是 VXC 的“本位”代号,家族也以它命名;Ghostlite 和 6acc60406 由 GXC 家族的 glc/gfc 初始化模块注册到同一个工厂中,在运行层面位于 VXC 内部。
VXC 继承了 PXC 引入的 fetch/load-core 拆分:asic_sw::driver::deepsea::vxc::vfc(vector fetch-core)和 vxc::vlc(vector load-core)。它的定义性新特征是 SparseCore,Viperfish 是第一代携带 SparseCore 的产品,而 SparseCore 的引入也对应着 BarnaCore 的退役。VXC HAL 实现也是四者中唯一一个大小为 216 字节而不是 208 字节的实现;额外的 8 字节是在偏移 +0xD0 处的一个标志字节。
本页遵循与 JXC、PXC 和 GXC 页面相同的组织方式。由于 GXC 注册到这个工厂中,代号分发的完整故事在这里讲述;GXC 页面涵盖 GXC 特有的内容(其编解码器和 sub-core ISA)。共享基类链见 HAL 家族。
重新实现时,契约是:
- 多版本注册表级分发:一个 global-ns 类、一个 vtable、三个按
TpuVersionkeyed 的 16 字节实例,由三个独立的初始化模块注册。 - 5 槽工厂 vtable(形状与 JXC/PXC 相同),以及带有
+0xD0skip-slicebuilder 标志的 216 字节TpuHalVxcHardwareImpl。 - 构造链 HardwareImpl → CommonHelper (48 B) → Chip (416 B) → Core (800 B),真正的按代号 switch 位于
InitializeDrivers。 vxc::vfc/vxc::vlcfetch/load 拆分、vxc::isa命名空间,以及统一的TpuVxcDriver(V2 descriptor,无 DMA-issuer)。
| 工厂类 | tpu::TpuHalVxcHardwareFactory(global-ns,唯一例外) |
| 服务的 TpuVersions | 3 — kViperfish (3), kGhostlite (4), k6acc60406 (5) |
| 工厂 vtable / vptr | _ZTV 0x21cabf70 / 已安装 vptr 0x21cabf80 |
| 工厂 typeinfo | _ZTI 0x21cabfa8(__si base → TpuHalHardwareFactoryBase 0x21d343f8) |
| HAL 实现类 / 大小 | TpuHalVxcHardwareImpl, 216 B (0xD8), vtable 0x21cabfc0 |
| 初始化模块 | vxc 0x213eed20 (v3), glc 0x213eb9e0 (v4), gfc 0x213e9f60 (v5) — 每个 1× Register |
| Fetch/load 拆分 | vxc::vfc + vxc::vlc(继承自 PXC) |
| DMA 引擎 | 统一的 tpu::TpuVxcDriver(无 issuer);DmaDescriptorV2 |
工厂绑定与注册
目的
VXC 将三个代号绑定到一个 HAL 实现。不同于 JXC(一个初始化模块,两次 Register 调用),VXC 使用三个独立的初始化模块,每个模块恰好调用一次 Register。原理相同:一个类、一个 vtable、N 个按 +8 处 TpuVersion keyed 的注册表条目;但注册点分散在 GXC 家族模块中。
入口点
google_init_module_tpu_hal_vxc_hardware_impl (0x213eed20) → Register(kHardware, 3, f) // Viperfish
google_init_module_tpu_hal_glc_hardware_impl (0x213eb9e0) → Register(kHardware, 4, f) // Ghostlite
google_init_module_tpu_hal_gfc_hardware_impl (0x213e9f60) → Register(kHardware, 5, f) // 6acc60406
(each: operator new(0x10); f[+8] = version; f[+0] = vptr 0x21cabf80; same vtable)
```text
### 算法
```c
function register_vxc_codename(version): // one of three init modules
f = operator_new(0x10) // 16-byte factory object
f[+8] = version // 3, 4, or 5
f[+0] = &VxcFactory_vtable + 0x10 // installed vptr 0x21cabf80 (SHARED)
s = TpuHalFactory::Register(kHardware /*0*/, version, unique_ptr(f))
CHECK(s == OK)
// CHECK strings byte-confirm the codename → factory binding:
// 0x94A3FA6 kViperfish, 0x94A4A6F kGhostlite, 0x94A3EF5 k6acc60406
// each: std::make_unique<tpu::TpuHalVxcHardwareFactory>(tpu::TpuVersion::kX)怪异点 — VXC 工厂 ctor 确实接受一个
TpuVersion(CHECK 字符串会把kViperfish/kGhostlite/k6acc60406传给make_unique),原因正是它必须服务三个版本;这点类似 JXC,不同于 PXC 的无参数 ctor。整个二进制中对工厂 vtable 0x21cabf70 恰好有三处引用,三处都是初始化模块的lea点。没有其他代码引用这个工厂类。
函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
google_init_module_tpu_hal_vxc_hardware_impl | 0x213eed20 | 注册 v3 (Viperfish) |
google_init_module_tpu_hal_glc_hardware_impl | 0x213eb9e0 | 注册 v4 (Ghostlite) — GXC 模块 |
google_init_module_tpu_hal_gfc_hardware_impl | 0x213e9f60 | 注册 v5 (6acc60406) — GXC 模块 |
TpuHalFactory::Register | 0x1fbb16a0 | 注册表插入(共享) |
工厂 vtable
目的
VXC 的工厂 vtable 与 JXC 和 PXC 具有相同的 5 槽形状;只有命名空间位置(全局 vs 匿名)和两个覆写函数地址不同。
Vtable 布局
| vaddr | 槽 | 解析到 | 基类/覆写 |
|---|---|---|---|
| 0x21cabf80 | 0 — ~TpuHalFactory() D2 | 0x0e723a80 (ret) | 继承 |
| 0x21cabf88 | 1 — ~TpuHalVxcHardwareFactory() D0 | 0x1d110e80 | 覆写 |
| 0x21cabf90 | 2 — HardwareFactoryBase::Create(wq) | 0x1e80f560 | 继承 |
| 0x21cabf98 | 3 — HardwareFactoryBase::CanCreate() | 0x1e80f520 | 继承 |
| 0x21cabfa0 | 4 — TpuHalVxcHardwareFactory::CreateImpl(wq) | 0x1d110e00 | 覆写 |
槽 1 编码 operator delete(this, 0x10),这个工厂是 16 字节,与所有四个家族一样。
算法 — CreateImpl
function TpuHalVxcHardwareFactory::CreateImpl(out, this, wq): // 0x1d110e00
obj = operator_new(0xD8) // 216 B = TpuHalVxcHardwareImpl
version = *(u32*)(wq + 8) // TpuVersion from work-queue+8
TpuHal::TpuHal(obj, version, wq) // base ctor 0x1e811c00: wq→+0x68, version→+0x78
*(void**)(obj + 0) = &VxcImpl_vtable + 0x10 // plant 0x21cabfc0 → 0x21cabfd0
*(void**)(obj + 0xC8) = nullptr // CommonHelper slot
*(byte*) (obj + 0xD0) = 0 // skip-slicebuilder flag (VXC-ONLY; the extra 8 B)
out.value = obj ; out.status = OK
return out
```text
> **怪异点 —** VXC 实现的**额外 8 字节**是在偏移 `+0xD0` 处的单个 bool(填充到 8 字节)。它是 *skip-slicebuilder / use-default-configured-properties* 开关:`CreateAndInitializeChips` 从 `FLAGS_deepsea_hal_test_skip_slicebuilder` (0x22398628) 设置它;`GetConfiguredProperties`(槽 8)读取它以在 `GetDefaultConfiguredProperties(topology)` 与 helper 的缓存状态之间选择;`PreTearDownChips`(槽 21)读取它以跳过 mesh teardown。这个标志只存在于 VXC 上,因为只有 VXC 有一个*可以*跳过的多芯片 slice-builder mesh。JXC/PXC 没有 slice-builder,因此没有标志,也因此是 208 字节。它**不是**稀疏状态指针。
### 注意事项
216 字节实现大小有双重证明:`CreateImpl` 中的 `operator new(0xD8)`,以及实现 D0 dtor 中的 `operator delete(this, 0xD8)`。在三个家族中,VXC 唯一覆写实现槽 18(`WaitForCoreDumpComplete`, 0x1d110f00);它的实现覆写数量是 8(槽 0、1、2、8、18、19、20、21)。见 [HAL 工厂覆写矩阵](hal-factory-override-matrix.md)。
---
## 工厂之下的构造链
### 目的
`TpuHalVxcHardwareImpl::CreateAndInitializeChips`(实现 vtable 槽 20,@ 0x1d110f20)驱动产品图,也是四个家族中唯一设置 `+0xD0` 标志并初始化 slice-builder mesh 的一个。
### 入口点
```text
TpuHalVxcHardwareImpl::CreateAndInitializeChips (0x1d110f20)
├─ TpuChipParts::CoreCount / SharedMemoryCount ── data-driven constraints
├─ this[+0xD0] = FLAGS_deepsea_hal_test_skip_slicebuilder & 1
├─ TpuHalVxcCommonHelper (48 B, 0x1d111a60) ── stored at impl+0xC8
├─ helper->InitializeDrivers(options, skip) ── per-codename switch (0x1d111a80)
├─ helper->MaybeInitializeSliceBuilder (0x1d113120)
└─ helper->CreateChips (0x1d113440)
└─ TpuChipVxcDriverImpl (416 B, 0x1d114120) ── + SyncFlagResources (296 B)
└─ core-factory lambda
└─ TpuCoreVxcDriverImpl (800 B, 0x1d118340) ── takes a TpuVxcDriver*算法 — 按代号 switch
function TpuHalVxcCommonHelper::InitializeDrivers(options, skip): // 0x1d111a80
chip_parts = *(options + 8) // chip-parts proto pointer
version = *(u32*)chip_parts // first u32 of chip-parts proto
variant = TpuChipParts::variant_name() // 0x20b1eb40 (sv: ptr in rax, len in rdx)
switch (version): // inline cmp $5 / $4 / $3
case 5 (6acc60406): if variant non-empty: InvalidArgument "6acc60406 unsupported variant " (0xa1d990c)
else if platform==0: scanner = sub_1FBA82A0 / CreateMultiVfScannerAdapter
case 4 (Ghostlite): if variant non-empty: InvalidArgument "ghostlite unsupported variant " (0xa1d992b)
else if platform==0: scanner = asic_sw::deepsea::DeepseaDeviceScanner (0x1fba7a20)
case 3 (Viperfish): scanner = vxc::vfc::VfDeviceScanner (0x1d1b0e20)
/* or vxc::vlc::VfDeviceScanner (0x1d1b0be0) when variant=="lite"
and FLAGS_vxc_virtual_function / qword_22398620 is set */
default: LogMessageFatal "TpuVersion <N> not supported." (line 501)
// a nonzero platform type in any case → MakeError "TPU Platform Type `%s` is not supported."
```text
> **注意 —** 这是整个 HAL 树中*唯一*真正按 `TpuVersion` 分支的 switch,并且它位于 `CommonHelper` 中,而不是工厂或实现中。工厂层在类上是统一的;实现方法不携带版本 switch。该分发位于 driver-init 层级,数据来自 chip-parts proto 的第一个 u32;它选择按代号的 device scanner,而不是分支 HAL 对象构造。
### 注意事项
每个 core 的 ctor 接受一个 `TpuVxcDriver*`,即统一的 VXC driver,而不是单独的 DMA-issuer(对比 JXC 的 `JfDmaIssuer*`)。`TpuVxcDriver` 构建 V2 DMA descriptor(`asic_sw::deepsea::dma::Descriptor`,14-bit sync flag),并通过 `EnableNHopRouting` / `SetRoutingStrategy` 配置 ICI routing。chip 对象还额外分配一个 296 字节的 `SyncFlagResources` 块。
---
## Driver 子命名空间清单
`asic_sw::driver::deepsea::vxc::` 承载 fetch/load 拆分和家族级 ISA。符号表确认的直接子命名空间:
| 子命名空间 | 作用 |
|---|---|
| `vxc::vfc` | **vector fetch-core** — fetch 侧指令流 |
| `vxc::vlc` | **vector load-core** — load 侧指令流 |
| `vxc::isa` | 家族级 ISA(170K 符号) |
fetch-core 之下是 `vxc::vfc::isa`(67K 符号)、`vxc::vfc::profiler`(40K 符号,含具名 `TraceEntry` 类,4015 符号),load 侧则是 `vxc::vlc::profiler`(12K 符号,`TraceEntry`,3001 符号)。SparseCore ISA bundles(`SparseCoreScsBundle`、`SparseCoreTacBundle`)位于 `vxc::vfc::isa` 之下,即 ISA/codec 层,而不是 216 字节 HAL 实现。每个 `vxc::vfc` / `vxc::vlc` 都携带自己的 `profiler::TraceEntry` 类,因此在[分类](sub-core-taxonomy.md)中二者都是 trace-entry sub-cores。
---
## 按代号差异
VXC 背后的三个代号在数据(chip-parts)和它们的 *codec* 类上不同,但共享一个 HAL 实现、一个 `TpuVxcDriver`、一个 V2 descriptor。Viperfish 在 `viperfish::isa` 下有自己的具名 worker(`EncoderVfTensorCore`、`DecoderVfTensorCore`);Ghostlite 和 6acc60406 详见 [GXC 页面](gxc-family.md)。
| 轴 | Viperfish (v3) | Ghostlite (v4) | 6acc60406 (v5) | 来源 |
|---|---|---|---|---|
| TpuVersion 枚举 | kViperfish = 3 | kGhostlite = 4 | k6acc60406 = 5 | `TpuVersionToString` 0x20b3a480 |
| ToString | "viperfish" | "ghostlite" | "6acc60406" | rel.ro 表 0x22011bf0 |
| 外部名称 | "TPU v5" (v5p / v5e) | "TPU v6 lite" (v6e) | "TPU7x" (tpu7x) | `TpuVersionToExternalName` 0x20b3a500 |
| 初始化模块 | vxc 0x213eed20 | glc 0x213eb9e0 | gfc 0x213e9f60 | symtab |
| Codec(`TpuCodec::Create` 0x1e835fa0 中的 case) | `CreateTpuCodecViperfish` (case 3) | `CreateTpuCodecGhostlite` (case 4) | anonymous `sub_1E838380` (case 5) | symtab |
| TensorCore / BarnaCore | 是 / 否 | 是 / 否 | 是 / 否 | TpuChipParts |
| SparseCore | 是(第一代) | 是 | 是 | TpuChipParts |
| Driver sub-core ISA | `vxc::vfc/vlc::isa` | `gxc::glc::isa` | `gxc::gfc::isa` | symtab |
| Flag 前缀 | `xla_vf_` (50), `xla_sc_` (164) | `xla_gf_` (44), `xla_sc_` | `xla_gf_`, `xla_sc_` | flag scan |
> **易错点 —** Ghostlite 和 6acc60406 注册到*这个*(VXC)工厂中,但它们的 driver 层 ISA 位于 **`gxc`** 命名空间(`gxc::glc::isa`、`gxc::gfc::isa`)下,而不是 `vxc` 下。只有 Viperfish 的 ISA 位于 `vxc` 下。对 v4/v5 而言,HAL 家族和 driver 子命名空间是解耦的,这也是两个页面互相交叉链接的原因。见 [GXC 家族](gxc-family.md)。
---
## 交叉引用
- [JXC 家族](jxc-family.md) — fused-dataflow 祖先,带有单独的 `JfDmaIssuer`
- [PXC 家族](pxc-family.md) — 引入了 VXC 继承的 fetch/load 拆分;V2 descriptor 的首个使用者
- [GXC 家族](gxc-family.md) — Ghostlite + 6acc60406,通过 glc/gfc 初始化模块注册到这个 VXC 工厂
- [Sub-Core 分类](sub-core-taxonomy.md) — fetch/load 拆分演化中的 `vfc`/`vlc`;SparseCore 引入
- [HAL 家族](hal-families.md) — 共享的 `TpuHalFactory` 基类链和 template-method `Create`
- [代号矩阵](tpu-version-codename-matrix.md) — 6 值 `TpuVersion` enum 和 HAL routing
- [HAL 工厂覆写矩阵](hal-factory-override-matrix.md) — 每个实现的 23 槽覆写表