PCI 设备 ID
地址适用于
libtpu-0.0.40-cp314wheel 中的 libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d,781,691,048 B)。其他版本会有所不同。
摘要
每个 Google TPU 都以 vendor ID 0x1ae0 (Google Inc.) 暴露在 PCIe 上。libtpu 不是从单个 device ID 识别硅片代际,而是从 12 字节的 asic_sw::DeviceIdentifiers 记录识别;该记录固定了 两个 device ID — 一个 header/function DID 和一个 chip DID — 以及 vendor ID、chip-revision mask 和 revision 值。xprof::tpu 命名空间中一小组 recognizer 函数会把传入记录与编译进来的 k*Identifiers 记录比较,并把匹配项映射到内部 device-type 整数;DeviceTypeFromDeviceIdentifiers 是把记录转换成该整数的唯一汇入口。
device-type 整数是独立于 TpuVersion 的枚举。它是 profiler/identity 轴:每个代号(以及同一代号内的每个芯片变体)都有自己的 device-type 值,因此 device-type 空间比六值 TpuVersion 空间更宽。本页记录 record layout、按代号和变体列出的完整 DID 表,以及 recognizer → device-type 汇入口 — 足以从原始 config-space 读取结果重新实现 TPU PCIe 枚举和代号归属。
对于重实现,契约是:
DeviceIdentifiers12 字节 record layout,以及每个 recognizer 实际比较哪些字段(8 字节 ID dword 和 offset-11 revision byte — 不是 offset-8 mask)。- 按代号 / 按变体列出的 hdrDID + chipDID + revision 表,包括两个没有 recognizer 匹配的 management-PF 记录。
DeviceTypeFromDeviceIdentifiers的 dispatch 顺序,以及每个分支存储的字面量 device-type 常量。
| Vendor ID(所有 TPU) | 0x1ae0 (Google Inc.) |
| 记录类型 | asic_sw::DeviceIdentifiers,12 个有意义字节(8 字节 ID dword + 4 字节 rev word) |
| 记录布局 | [VID:2][hdrDID:2][subVID:2][chipDID:2][revmask:1][pad:2][rev:1],little-endian |
| Dispatch 汇入口 | xprof::tpu::DeviceTypeFromDeviceIdentifiers @ 0xf6993a0 |
| 被调用的 recognizers | IsGlc @ 0xf6992a0 (Ghostlite, TpuVersion 4),IsGfc @ 0xf699320 (6acc60406, TpuVersion 5) |
| 反向映射 | xprof::tpu::DeviceIdentifiersFromDeviceType @ 0xf6996e0 — device-type int → canonical record |
| 标识符记录表基址 | 0x0bdf3c0c (kJellyfishIdentifiers) … 0x0bdf3ce8(结束标记 s_44716) |
DeviceIdentifiers 记录布局
每个 k*Identifiers 记录在 .rodata 中携带 12 个有意义字节:一个 8 字节 ID dword (VID‖hdrDID‖subVID‖chipDID),后接一个 4 字节 revision word。asic_sw::driver::deepsea::jxc::Driver::GetDeviceIdentifiers (0xe794560) 会把这些精确复制到 live record 中 — *(_QWORD *)v3(8 字节 ID dword)和 *(_DWORD *)(v3 + 8)(4 字节 rev word)— 确认了 8+4 切分。recognizers 会把该记录读回为一个 64-bit dword(*(_QWORD *)record,即 ID dword)加上 offset 11 处的单个 revision byte(*((_BYTE *)record + 11))。读取 0x0bdf3ca0 处的 Ghostlite App PF 记录:
0bdf3ca0: e0 1a | 6e 00 | e0 1a | d1 00 | 12 | 00 00 | 00
VID hdrDID subVID chipDID msk pad rev
0x1ae0 0x006e 0x1ae0 0x00d1 0x12 ---- 0x00
offset 0 2 4 6 8 9 10 11
```text
| 字段 | Offset | 宽度 | 含义 |
|---|---|---|---|
| VID | 0 | 2 | PCI vendor ID — 始终为 `0x1ae0` (Google) |
| hdrDID | 2 | 2 | Header / PCI-function device ID(区分 PF / VF / management-PF) |
| subVID | 4 | 2 | Subsystem vendor ID — 也是 `0x1ae0` |
| chipDID | 6 | 2 | Chip device ID — 硅片代际判别项 |
| revmask | 8 | 1 | Chip-revision mask — 除 Ghostlite (`0x12`) 外,每个代号都是 `0xff` |
| (pad) | 9 | 2 | 4 字节 rev word 内部的零填充 |
| rev | 11 | 1 | Revision-equality byte — recognizers 比较的项(`v4 == record[11]`) |
> **陷阱 —** 仅 chip DID **不能** 标识一个设备。所有三个 Ghostlite functions(App PF / App VF / Mgt PF)共享 chip DID `0x00d1`;它们只在 hdrDID (`0x006e`/`0x006f`/`0x0070`) 上不同。只按 chip DID 建 key 的重实现会把三个 PCI functions 折叠成一个,并错误路由 management interface。recognizers 比较的是 **完整** 记录(VID、通过 low dword 的 hdrDID、通过 48-bit-shift 项的 chipDID,以及 offset-11 revision byte),而不是孤立的 chip DID。
>
> **陷阱 —** recognizers 测试的 revision 字节在 offset **11**,不是 offset 8。Offset 8 保存 chip-revision *mask* (`revmask`);offsets 9–10 是零填充;offset 11 是 revision-equality byte。对 Ghostlite 来说这个区别很明确:`revmask` (offset 8) 是 `0x12`,而 revision-equality byte (offset 11) 是 `0x00`。把 offset 8 与按记录 revision 比较的重实现会误匹配 Ghostlite,而 Ghostlite 正是唯一 mask 不同于 `0xff` 的一代。
recognizer 比较是四项 `&&`(在 `IsGfc` 中可逐字看到):low dword 等于匹配记录的 low dword (VID+hdrDID),chip-VID word `WORD2 == 0x1ae0`(十进制 `6880`),一个固定 high word 中 chip DID 的 `(record ^ expected) >> 48 == 0` 项,以及 `record[11] == expected_rev`。dispatch 汇入口中的每个分支都内联重复同样形状。
---
## DID 表
直接读取自 `0x0bdf3c0c`–`0x0bdf3ce8` 处的 `.rodata` 标识符记录块。Header/chip DIDs 和两个 revision 字节均由字节解码;device-type 列是 `DeviceTypeFromDeviceIdentifiers` 存储的字面量常量(见下文)。每行 VID 都是 `0x1ae0`。`External name` 列是 `TpuVersionToExternalName` 显示字符串,**不是** 内部 `TpuVersion` 整数(Ghostlite 是 `TpuVersion` 4 但显示为 `TPU v6 lite`;6acc60406 是 `TpuVersion` 5 但显示为 `TPU7x`)— 关于 codename ↔ `TpuVersion` ↔ external-name 映射,见 [代号矩阵](tpu-version-codename-matrix.md)。
`rev-mask` 列是 record offset 8 处的字节;`rev[11]` 是 offset 11 处 recognizer 实际比较的 revision-equality byte(见上面的布局)。每条记录的 `revmask`/`rev[11]` 对都直接从 `.rodata` 读取。`External name` 是该行 `TpuVersion` 的名义 `TpuVersionToExternalName` 字符串;`lite` 判别项是 *运行时* 变体 `string_view`(不是 PCI 记录的一部分),所以 `lite` 代号(Puffylite、Viperlite)只有在提供该 variant arg 时才显示为 `… lite`。
| 代号 / 变体 | External name | hdrDID | chipDID | rev-mask | rev[11] | Device-type | 记录地址 | 已识别? |
|---|---|---|---|---|---|---|---|---|
| Jellyfish | TPU v2 | `0x0027` | `0x004e` | `0xff` | `0x00` | **3** | `0xbdf3c0c` | funnel(内联) |
| Dragonfish | TPU v3 | `0x0027` | `0x004f` | `0xff` | `0x00` | **5** | `0xbdf3c18` | funnel(内联) |
| Pufferfish B0 Mfg | TPU v4 | `0x005e` | `0x0050` | `0xff` | `0x10` | **7** | `0xbdf3c28` | funnel(内联) |
| Pufferfish B0 Water | TPU v4 | `0x005e` | `0x0051` | `0xff` | `0x10` | **7** | `0xbdf3c34` | funnel(内联) |
| Pufferfish B0 Air | TPU v4 | `0x005e` | `0x0052` | `0xff` | `0x10` | **7** | `0xbdf3c40` | funnel(内联) |
| Puffylite (pxc::plc) | TPU v4 lite | `0x0056` | `0x007b` | `0xff` | `0x00` | **8** | `0xbdf3c4c` | funnel(内联) |
| Viperlite A0 PF | TPU v5 lite | `0x0063` | `0x00ae` | `0xff` | `0x00` | **11** | `0xbdf3c58` | funnel(内联) |
| Viperlite A0 VF | TPU v5 lite | `0x0063` | `0x00ae` | `0xff` | `0x01` | **11** | `0xbdf3c64` | funnel(内联) |
| Viperlite A1 PF | TPU v5 lite | `0x0063` | `0x00af` | `0xff` | `0x00` | **11** | `0xbdf3c70` | funnel(内联) |
| Viperlite A1 VF | TPU v5 lite | `0x0063` | `0x00af` | `0xff` | `0x01` | **11** | `0xbdf3c7c` | funnel(内联) |
| Viperfish PF | TPU v5 | `0x0062` | `0x00ac` | `0xff` | `0x00` | **10** | `0xbdf3c88` | funnel(内联) |
| Viperfish VF | TPU v5 | `0x0062` | `0x00ad` | `0xff` | `0x00` | **10** | `0xbdf3c94` | funnel(内联) |
| Ghostlite App PF | TPU v6 lite | `0x006e` | `0x00d1` | `0x12` | `0x00` | **13 (0xd)** | `0xbdf3ca0` | `IsGlc` |
| Ghostlite App VF | TPU v6 lite | `0x006f` | `0x00d1` | `0x12` | `0x00` | **13 (0xd)** | `0xbdf3cac` | `IsGlc` |
| Ghostlite Mgt PF | TPU v6 lite | `0x0070` | `0x00d1` | `0x12` | `0x00` | (none) | `0xbdf3cb8` | 未识别 |
| 6acc60406 PF | TPU7x | `0x0075` | `0x00f2` | `0xff` | `0x00` | **12 (0xc)** | `0xbdf3cc4` | `IsGfc` |
| 6acc60406 VF | TPU7x | `0x0076` | `0x00f2` | `0xff` | `0x00` | **12 (0xc)** | `0xbdf3cd0` | `IsGfc` |
| 6acc60406 Mgt PF | TPU7x | `0x0077` | `0x00f2` | `0xff` | `0x00` | (none) | `0xbdf3cdc` | 未识别 |
> **特性 —** 两条 management-PF 记录(`0x0070`/Ghostlite,`0x0077`/6acc60406)存在于 `.rodata` 表中,但 **没有 device-type recognizer 会匹配它们**。`IsGlc` 只比较 `kGhostliteChipAppPFIdentifiers` (`0x006e`) 和 `kGhostliteChipAppVFIdentifiers` (`0x006f`);`IsGfc` 只比较 `0x0075` (PF) 和 `0x0076` (VF) dword。`kGhostliteChipMgtPFIdentifiers` 从 HAL `hardware_attributes_factory.cc` init module 引用,而不是从 `xprof::tpu` recognizers 引用 — management function 会为 HAL routing 注册,但有意不分配 profiler device-type。把 Mgt-PF 记录送入 `DeviceTypeFromDeviceIdentifiers` 的重实现会得到 `"Unsupported device identifiers"` 错误,这是设计行为。
直接从二进制读取、确认最新两代的字节块:
```text
ID dword rev word decode
0bdf3ca0: e01a 6e00 e01a d100 1200 0000 Ghostlite App PF hdr 006e chip 00d1 msk 12 rev[11] 00
0bdf3cac: e01a 6f00 e01a d100 1200 0000 Ghostlite App VF hdr 006f chip 00d1 msk 12 rev[11] 00
0bdf3cb8: e01a 7000 e01a d100 1200 0000 Ghostlite Mgt PF hdr 0070 chip 00d1 msk 12 rev[11] 00
0bdf3cc4: e01a 7500 e01a f200 ff00 0000 6acc60406 PF hdr 0075 chip 00f2 msk ff rev[11] 00
0bdf3cd0: e01a 7600 e01a f200 ff00 0000 6acc60406 VF hdr 0076 chip 00f2 msk ff rev[11] 00
0bdf3cdc: e01a 7700 e01a f200 ff00 0000 6acc60406 Mgt PF hdr 0077 chip 00f2 msk ff rev[11] 00
0bdf3ce8: 73 5f 34 34 37 31 36 00 "s_44716\0" (block-end tag)特性 — Ghostlite (
TpuVersion4) 是唯一 offset-8revmask为0x12而不是0xff的一代。该 mask 字节是存储字段 — recognizers 不会 读取它,recognizers 按 offset-11 revision-equality byte 建 key(每条 Ghostlite 记录都是0x00)。尽管如此,静态记录中的0x12仍是可靠的 Ghostlite 指纹。镜像 recognizer 逻辑的重实现应比较 byte 11,而不是 byte 8;想验证整个存储记录的实现则应预期 Ghostlite 在 byte 8 为0x12,其他位置为0xff。注意 — Ghostlite 记录有命名符号 —
asic_sw::deepsea::gxc::glc::kGhostliteChip{AppPF,AppVF,MgtPF}Identifiers(三个都有,包括 Mgt PF)— 且IsGlc引用 App PF / App VF 符号。6acc60406 记录是 匿名的(二进制中不存在k6acc60406*Identifiers符号);IsGfc比较的是内联加载的字面量立即数(PF 为0x751ae0,VF 为0x761ae0,chip-DID 项0x00f2折入0xf21ae000761ae0xor mask)。反向映射DeviceIdentifiersFromDeviceType通过&dword_BDF3CD0(0xbdf3cd0处的 VF 记录)抵达匿名 v5 记录,这是二进制中唯一以符号形式保留的句柄。0xbdf3ce8处尾随的s_44716tag string 标记匿名 gfc 记录的结束。
Recognizers — IsGlc 和 IsGfc
目的
两个最新代 recognizer 回答“这条记录是不是 Ghostlite (glc) 设备?”以及“这条记录是不是 6acc60406 (gfc) 设备?”。它们是 dispatch 汇入口 调用 的仅有两个 recognizers — 所有更早代号都由汇入口主体中的内联比较匹配(见下文),而更早的 sub-core families 有并行的独立 recognizers(IsDfc、IsPlc、IsPfc、IsVlc、IsVfc),但汇入口不使用它们。两者都返回 bool。每个只识别 App PF 和 App VF functions;两者都不匹配 management-PF 记录。
算法
bool IsGfc(record): // 0xf699320
id = *(uint64_t*)record // VID|hdrDID|subVID|chipDID dword
rev = record[11] // revision-equality byte (offset 11)
// VF first (the fast branch): hdrDID 0x0076, chip 0x00f2
if (id & 0xffffffff)==0x761ae0 && WORD2(id)==0x1ae0
&& ((id ^ 0xF21AE000761AE0) >> 48)==0 && rev==*(byte*)0xbdf3cdb: // VF rev[11] = 0x00
return true // chip DID 0x00f2 pinned in high word
// PF fallback: hdrDID 0x0075, chip 0x00f2
return (id & 0xffffffff)==0x751ae0 && WORD2(id)==0x1ae0
&& ((id ^ 0xF21AE000751AE0) >> 48)==0 && rev==*(byte*)0xbdf3ccf // PF rev[11] = 0x00
// Mgt PF (hdrDID 0x0077) is NOT compared — falls through to false
bool IsGlc(record): // 0xf6992a0
// identical shape, comparing against the NAMED
// kGhostliteChipAppVFIdentifiers (fast branch, hdrDID 0x006f)
// and kGhostliteChipAppPFIdentifiers (fallback, hdrDID 0x006e),
// chip DID 0x00d1, rev[11]==0x00 for both.
// Mgt PF (hdrDID 0x0070) is NOT compared.
...
```text
`0xF21AE000761AE0` 立即数按 little-endian 解码为 `e0 1a 76 00 00 e0 1a f2`:VID `0x1ae0`、hdrDID `0x0076`、subVID `0x1ae0`、chipDID `0x00f2`。`>> 48` 项隔离顶端 16 位(chip DID `0x00f2`),所以比较会同时固定 function DID 和 chip DID。反编译器显示的十进制形式是 `7740128`(`0x761ae0`,VF fast branch)和 `7674592`(`0x751ae0`,PF fallback)。
### 函数映射
| 函数 | 地址 | 作用 |
|---|---|---|
| `xprof::tpu::IsGlc` | `0xf6992a0` | 识别 Ghostlite App PF/VF 记录 — chip `0x00d1` (`TpuVersion` 4) |
| `xprof::tpu::IsGfc` | `0xf699320` | 识别 6acc60406 App PF/VF 记录 — chip `0x00f2` (`TpuVersion` 5) |
| `xprof::tpu::DeviceTypeFromDeviceIdentifiers` | `0xf6993a0` | 将记录映射到其 device-type 整数(最后调用 `IsGlc`/`IsGfc`) |
| `xprof::tpu::DeviceIdentifiersFromDeviceType` | `0xf6996e0` | 反向:device-type int → 每代一个 canonical record |
| `xprof::tpu::{IsDfc,IsPlc,IsPfc,IsVlc,IsVfc}` | `0xf699000`, `0xf699040`, `0xf699080`, `0xf699140`, `0xf699220` | 独立的按代号 recognizers(汇入口不调用) |
> **注意 —** `DeviceIdentifiersFromDeviceType` (`0xf6996e0`) 是反向映射。对每个 device-type 整数,它返回一个代表性记录:3→Jellyfish,5→Dragonfish,7→Pufferfish B0 Water,8→Puffylite,10→Viperfish VF,11→Viperlite A0 VF,12→匿名 6acc60406 VF 记录(`&dword_BDF3CD0`),13→Ghostlite App VF。未知 device-type 返回 `"Unsupported device type"`(`device_identifiers_utils.cc:191`)。注意它并不是真正的逆映射 — 拥有多个变体记录的一代会折叠到单个 canonical 记录(例如所有三个 Pufferfish B0 变体都只映射回 Water)。
---
## `DeviceTypeFromDeviceIdentifiers` — 汇入口
### 目的
这是把 `DeviceIdentifiers` 记录转换为 profiler device-type 整数的唯一函数。它是一个扁平的 `if/else if` 内联记录比较链;更早的代号首先由直接相等性测试,两个最新代则落到 `IsGlc` / `IsGfc`。没有匹配时,它返回 `absl::Status` 错误(`"Unsupported device identifiers"`,`device_identifiers_utils.cc:152`)。
### 算法
```c
DeviceType DeviceTypeFromDeviceIdentifiers(record): // 0xf6993a0
if matches(kJellyfishIdentifiers): return 3
if matches(kDragonfishIdentifiers): return 5
if matches(kPuffyliteChipIdentifiers): return 8
if matches(PufferfishB0{Mfg,Water,Air}): return 7
if matches(Viperlite{A0,A1}{PF,VF}): return 11
if matches(Viperfish{PF,VF}): return 10
if IsGlc(record): return 13 // 0xd — Ghostlite (TpuVersion 4)
if IsGfc(record): return 12 // 0xc — 6acc60406 (TpuVersion 5)
return Error("Unsupported device identifiers") // :152注意 — Ghostlite→
0xd/ 6acc60406→0xc的 device-type 绑定固定在字面量 store 上:DeviceTypeFromDeviceIdentifiers直接写入常量 — 在IsGlc分支上*(_DWORD*)(result+8) = 13,在IsGfc分支上= 12。6acc60406 PCI 记录存在于.rodata的0xbdf3cc4–0xbdf3ce8(匿名、无符号),且 v5 chip DID0x00f2同时由这些字节和IsGfc立即数确认。
Device-Type 映射
从汇入口恢复出的完整 device-type 整数空间。注意 device-type 比 TpuVersion 更密集:一个代号内的芯片变体会折叠为一个 device-type(所有 Pufferfish B0 → 7;所有 Viperlite → 11),而预生产 Puffylite 有自己的值 (8)。
| Device-type | 代号 / family | TpuVersion |
|---|---|---|
| 3 | Jellyfish | 0 |
| 5 | Dragonfish | 1 |
| 7 | Pufferfish (B0 Mfg/Water/Air) | 2 |
| 8 | Puffylite (pxc::plc pre-production) | (2 family) |
| 10 | Viperfish (PF/VF) | 3 |
| 11 | Viperlite (A0/A1 PF/VF) | (3 family) |
12 (0xc) | 6acc60406 (gfc) | 5 |
13 (0xd) | Ghostlite (glc) | 4 |
特性 — device-type 整数不按
TpuVersion顺序排列,并且 Ghostlite (TpuVersion4) 得到 更高 的 device-type (13),而 6acc60406 (TpuVersion5) 得到 12。device-type 由 recognizer 评估顺序和 identity 便利性分配,而不是由时间顺序分配。重实现不能从 device-type 值推断代际顺序;应使用 chip-DID →TpuVersion映射。类似地,汇入口先测试 Puffylite (8),再测试 Pufferfish B0 变体 (7) — 内联比较顺序也不遵循 device-type 整数。
DID → TpuVersion 查找路径
原始 config-space 读取结果通过这条链解析为 TpuVersion:
PCI config (VID 0x1ae0, hdrDID, chipDID, rev)
└─ build asic_sw::DeviceIdentifiers (12 B)
└─ DeviceTypeFromDeviceIdentifiers (0xf6993a0) ── record → device-type int
├─ direct record compares (Jellyfish … Viperfish)
└─ IsGlc (0xf6992a0) / IsGfc (0xf699320) ── Ghostlite / 6acc60406
device-type → codename → TpuVersion (table above)
```text
codename → `TpuVersion` 方向由 `0x22011bf0` 处的 `TpuVersionToString` rel.ro pointer table 固定(六个 `R_X86_64_RELATIVE` relocations 按 enum 顺序命名 `jellyfish`…`6acc60406`);见 [代号矩阵](tpu-version-codename-matrix.md)。chip-DID → codename 绑定由本页 DID 表提供。
---
## 交叉引用
- [代号矩阵](tpu-version-codename-matrix.md) — device-type 列映射到其中的 `TpuVersion` enum ↔ codename 真值表
- [Marketing / Cloud 命名](marketing-cloud-naming.md) — codename ↔ Cloud-TPU display name(v6e/TPU7x 对照)
- [被取代标签修正列表](codename-superseded-labels.md) — v5 chip-DID 和 device-type 标签固定
- [HAL Families](hal-families.md) — 消耗已识别设备的 JXC/PXC/VXC factory routing
- [Chip Parts binarypb](chip-parts-binarypb.md) — 携带 DID 和 core-count metadata 的嵌入式 per-chip proto