6acc60406 包
本页上的每个偏移、值和地址都逐字节读取自
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)。其他版本会有所不同。
摘要
6acc60406(TpuVersion::k6acc60406 = 5,外部名称 TPU7x)是这个 build 中最新的 TensorCore 代。它的包是一个 64 字节(512 位)VLIW 发射 word,宽度与 Viperfish 和 Ghostlite 相同,并由 gxc::gfc::isa::...GetBytesPerBundle @ 0x1d375a40 返回 0x40 确认。让它成为独立线缆格式的不是宽度,而是槽位 bit 布局:这一代的 ISA 位于 asic_sw::deepsea::gxc::gfc(general fetch-core)子核心命名空间,并且每个槽位 encoder 都把字段打包到相对于 Ghostlite(gxc::glc)发生偏移的字节/bit 位置。本页以可重新实现的粒度记录该布局:包含绝对 bit 偏移的完整槽位图、它与 Ghostlite 的差异(MXU latency/format 重映射,包括 FP8 e4m3/e5m2 dtype 集、result-slot 重映射,以及共享的 GhostliteTensorCoreEmitter EmitX 叶子),以及此代号的定义性特征:它的 codec 是匿名的。TpuCodec::Create case 5 分发到未命名 factory sub_1E838380,二进制中任何位置都没有 CreateTpuCodec6acc60406 符号。
与每个 V5+ 代一样,6acc60406 包字节完全由 proto-bundle <Slot>Encoder::Encode codec 产生:这一代的默认 LLVM-MC InstBits 表全为零。每个 encoder 读取自己的 typed proto 子消息,并调用通用 bit-packer BitCopy(dst, dst_bit, src, src_bit, nbits) @ 0x1fa0a900,把每个字段放入 64 字节缓冲区中的固定绝对 bit。Orchestrator EncodeBundle @ 0x1e838cc0 按模板参数顺序遍历逐槽位 encoder;gfc 命名空间的 encoder 集就是这一代有效的 kIsaTable。关于模型上下文(什么是包、no-scoreboard VLIW 契约、空槽位 kNeverExecute 约定),见 包模型。
对重新实现而言,契约是:
- 64 字节宽度,以及它通过匿名 codec
sub_1E838380(TpuCodec::Create的 case 5)选择,而不是具名的CreateTpuCodec6acc60406。 gfc槽位偏移:每个功能槽位都是 512 bit 缓冲区中的连续 bit 窗口,由BitCopy从 typed proto 子消息填充;逐槽位 predicate selector 位于槽位高端,opcode discriminator 位于其下方。- 两个 GF 相对 Ghostlite 的专属差异:(1) 专用双 predicate 槽位(
TensorCorePredicates,bits 496..505 上的 2×(4+1)-bit 池)加上逐槽位 2-bit predicate selector,取代 Ghostlite 的逐槽位 4+1-bit predicate 字段;(2) MXU format 重映射:仅浮点 dtype 集{F32, E4m3, Bf16, E5m2}(没有整数 matmul)、bit 62 上的 matmul opcode,以及重映射到 bits 11/20/323 的 result 槽位。 - Decode 侧的逆过程:
gfc::isa::...Decoder::Decode通过逐字段GetConcatenatedValueaccessor 和逐 dtypeOpcode::Matchesmask predicate 把字节读回。
| TpuVersion | k6acc60406 = 5(外部 TPU7x);见 代号矩阵 |
| 子核心 ISA | asic_sw::deepsea::gxc::gfc::isa(general fetch-core);见 GXC 家族 |
| 包宽度 | 64 B / 512 bit:gfc::...GetBytesPerBundle @ 0x1d375a40 return 0x40 |
| Codec | 匿名:TpuCodec::Create @ 0x1e835fa0 case 5 → sub_1E838380;没有 CreateTpuCodec6acc60406 符号 |
| Encode orchestrator | EncodeBundle @ 0x1e838cc0 → gfc::TensorCoreCodecBase<…> worker @ 0x1d371540 |
| Bit packer | BitCopy(dst, dst_bit, src, src_bit, nbits) @ 0x1fa0a900(LSB-first,bit 粒度) |
| Emitter 叶子 | GhostliteTensorCoreEmitter @ 0x14221840(共享;cell 12 复用 Ghostlite 的) |
| MXU dtype 集 | {F32, E4m3, Bf16, E5m2}:仅浮点,显式命名 FP8(相对 Ghostlite 的 8 个) |
| Predicate 模型 | 专用双 predicate 槽位 + 逐槽位 2-bit selector |
匿名 Codec(sub_1E838380)
其他每个 TensorCore 代都具象化为一个具名 C++ codec factory:TpuCodec::Create(0x1e835fa0)是一个 switch(TpuVersion),其前五个分支调用已 demangle 的 CreateTpuCodec<Codename> 构造器。第六个分支,也就是 case 5 的 6acc60406 codec,调用一个匿名 factory。这不是符号化失败;它是该 build 的结构性属性,也是这一代最有辨识度的事实。
反汇编没有歧义:
TpuCodec::Create(TpuVersion) @ 0x1e835fa0 (jump table on version):
case 0 -> call 0x1e840ac0 CreateTpuCodecJellyfish
case 1 -> call 0x1e8360e0 CreateTpuCodecDragonfish
case 2 -> call 0x1e841fa0 CreateTpuCodecPufferfish
case 3 -> call 0x1e843f00 CreateTpuCodecViperfish
case 4 -> call 0x1e83bce0 CreateTpuCodecGhostlite // named
case 5 -> call 0x1e838380 (anonymous; no CreateTpuCodec6acc60406)
```text
符号表扫描恰好返回五个 `CreateTpuCodec*` factory:`Jellyfish`、`Dragonfish`、`Pufferfish`、`Viperfish`、`Ghostlite`,并且**没有** `CreateTpuCodec6acc60406`。case-5 目标 `0x1e838380` 完全没有携带 `CreateTpuCodec` 符号;它是一个三行叶子函数,执行 `operator new(8)` 分配 8 字节对象并安装未命名 vtable `off_21D358A8`:
```text
sub_1E838380 @ 0x1e838380:
result = operator new(8);
*result = &off_21D358A8; ; vtable, no named _ZTV / _ZTI
return result;所以 6acc60406 codec 是由一个未命名 factory 内联构造的,其 vtable 没有已 demangle 的 _ZTV / _ZTI 符号:这在结构上正好与 Ghostlite 的具名 TpuCodecGhostlite(vtable 0x21d35c00)相反。
0x1e835fab 处的 jump-table 锚点说明 case-5 路径确实是 gfc codec,而不是偶然分支:分发前紧邻的 lea 引用了以下 type string:
jellyfish::isa::EncoderBase<
asic_sw::deepsea::gxc::gfc::isa::SparseCoreScsCodecBase<
SparseCoreScsBundle, ScsScalarSubBundle, SparseCoreScalarAlu0Decoder, …Encoder,
SparseCoreScalarAlu1…, SparseCoreScalarImmediates…, SparseCoreVectorScalar…,
SparseCoreDma…, SparseCoreScsScalarMisc…, SparseCoreStream…, SparseCoreDmaFields>,
…, SparseCoreScsProgram, TpuSequencerType=3>
```text
也就是 `gxc::gfc::isa` SCS codec base,键为 `TpuSequencerType 3`。因此匿名 codec 安装的是 `gfc` 命名空间 encoder。
这种不对称性还由三个独立角度佐证;它们都只用混淆 tag 命名这一代,从未把它命名为 C++ 类:
- **仅字符串注册。** 这一代以 `6acc60406BundleRestrictions`、`6acc60406TensorcoreEmitter`、`6acc60406HardwareScanner` 形式出现:它们是字符串字面量,不是已 demangle 的类。相比之下,Ghostlite 有完整具名的 `TpuCodecGhostlite`(vtable `0x21d35c00`)。
- **共享 emitter 叶子。** 键 `(5, TensorCoreSequencer)` 对应的 pair-keyed `IsaEmitter` registry cell 复用 `GhostliteTensorCoreEmitter` @ `0x14221840`:不存在 `Trillium`/`6acc60406` emitter 类。`gfc` 与 `glc` 的分裂发生在 codec 内部(`gfc::TensorCoreCodecBase` 4-VALU 模板),而不是 leaf 处。
- **没有 Target 子类。** LLVM `Target` 家族止于 `GhostliteTarget`(`0x21cc85f8`);6acc60406 路径复用它。这是相同的 gen-merge 模式。
> **陷阱 — 不要虚构 `TpuCodec6acc60406` 或 `Trillium` 类。** 字符串 `Trillium`、`Ironwood` 和 `Ghostfish` 在这个二进制中出现零次。重新实现若为 generation 5 发出具名 codec/factory/target,就会偏离二进制结构;正确形状是*复用 Ghostlite leaf 类,通过匿名 codec 分发,并把 `gfc` encoder 集键定到 version 5*。规范名称是 `6acc60406`;唯一面向公开的名称是 `TPU7x`。
>
> **注 — `gfc` 是 6acc60406 子核心,不是 Ghostlite 的子核心。** 一个命名风险是:`gfc` 看起来与 `glc` 相邻,但 [GXC 家族](../targets/gxc-family.md) 固定了 **Ghostlite (v4) = `glc`**(general load-core)和 **6acc60406 (v5) = `gfc`**(general fetch-core)。本页中每个 `gfc::*` 符号都是 6acc60406 代,每个 `glc::*` 符号都是 Ghostlite。
---
## 包宽度与 Encode 路径
宽度由字节锚定。`asic_sw::deepsea::gxc::gfc::isa::...GetBytesPerBundle` @ `0x1d375a40` 是一个两指令叶子函数:
```text
0x1d375a40: mov eax, 0x40 ; 64
0x1d375a45: ret因此 6acc60406 TensorCore 包是 64 字节,确认了 包模型 中的说法:Viperfish(v3)、Ghostlite(v4)和 6acc60406(v5)都共享 64 字节发射 word,只在槽位布局上不同。宽度通过 codec-metadata registry 到达(codec_metadata::BundleSizeBytes @ 0x1ecf7180 → GetMetadataOrDie → vtable),不是固定 switch;不存在 Trillium/6acc60406CodecMetadata 符号,注册条目复用 64 字节 v5+ 类形状。
TensorCore encoder 本身由共享 factory tpu::internal::CreateEncoderGlGf @ 0x1e831020 构建,这也是 Ghostlite 使用的同一个 factory。它根据 TpuVersionFromProtoOrDie 分支:v3 == 4 构造 gxc::glc::isa::TensorCoreCodecBase(对象大小 0xF0,vtable off_21CBFCD0),而 v3 == 5 构造 gxc::gfc::isa::TensorCoreCodecBase(对象大小 0xF8,vtable off_21CC22E0);除已处理的 TC / SCS / TAC case 外,任何 sequencer type 都会命中 LogMessageFatal("Unsupported sequencer type")。这个单一 factory 同时容纳两代,是 GL/GF encoder 共享的具体实现:gfc 与 glc 的分裂是 CreateEncoderGlGf 内部的 TpuVersion 分支,而不是两个独立 factory。glc 分支见 Ghostlite 包。
Encode 路径是通用的 V5+ 两阶段链:
LLO op ──(EmitX, proto population)──▶ proto sub-message (present-bit + fields)
proto sub-message ──(<Slot>Encoder::Encode, BitCopy)──▶ absolute bit window in 64-B buffer
```text
`EncodeBundle` @ `0x1e838cc0` 是 orchestrator:它按 `TpuSequencerType`(TC / SCS / TEC)分发,为 TC 路径构造 `gfc::TensorCoreCodecBase<…>`,并调用 worker @ `0x1d371540`;该 worker 按模板参数顺序对共享 64 字节缓冲区调用每个槽位的 `Encoder::Encode`。每个字段写入都是一个 `BitCopy(buffer, dst_bit, &field, 0, width)` 调用到 `0x1fa0a900`:bit 粒度、LSB-first,其中 `dst_bit` 是包中的绝对 bit(byte = `dst_bit >> 3`,bit-in-byte = `dst_bit & 7`)。下面的表为每个字段给出 `(dst_bit, width)` 三元组,全部由具名 encoder 中 `BitCopy` 调用前的字面 `mov esi,<dst_bit>` / `mov r8d,<width>` 立即数验证。
---
## 槽位图:绝对 Bit 偏移(64 字节 / 512-bit 缓冲区)
包被划分为标准 V5+ 槽位类。下表是合并后的 6acc60406(`gfc`)槽位图;bit 0 是 byte 0 的 LSB。每一项都锚定到写入它的具名 `gfc::isa::...Encoder::Encode`,以及固定偏移的 `BitCopy` 立即数。
| 槽位 / 字段 | dst_bit(十进制) | hex | width | Encoder(`gfc::isa`)@ |
|---|---:|---|---:|---|
| **Predicate 池** `pred_0` reg | 501 | 0x1f5 | 4 | `TensorCorePredicatesEncoder::Encode` @ `0x1f86e500` |
| `pred_0` invert | 505 | 0x1f9 | 1 | (same) |
| `pred_1` reg | 496 | 0x1f0 | 4 | (same) |
| `pred_1` invert | 500 | 0x1f4 | 1 | (same) |
| **Sequencer** 逐槽位 2-bit pred selector | 489 | 0x1e9 | 2 | `TensorCoreScalarAlu0Encoder::Encode` @ `0x1f87b420` |
| seq opcode-HIGH / family | 483 | 0x1e3 | 6 | (same) |
| seq opcode-LOW / discriminator | 478 | 0x1de | 5 | (same; branch helpers @ `0x1f87f5c0`+) |
| seq x-target / 第 2 操作数 | 472 | 0x1d8 | 6 | (same) |
| seq call dest (return-addr) sreg | 467 | 0x1d3 | 5 | (same) |
| **Immediate** 槽位 0(branch/call/sync offset) | 423 | 0x1a7 | 20 | `TensorCoreImmediatesEncoder::Encode` @ `0x1f86de20` |
| imm 槽位 1 | 403 | 0x193 | 20 | (same) |
| imm 槽位 2 | 383 | 0x17f | 20 | (same) |
| imm 槽位 3 | 363 | 0x16b | 20 | (same) |
| imm 槽位 4 | 343 | 0x157 | 20 | (same) |
| imm 槽位 5 | 323 | 0x143 | 20 | (same) |
| **VALU 槽位 0** opcode | 293 | 0x125 | 8 | `TensorCoreVectorAlu0Encoder` family |
| VALU0 dst vreg | 276 | 0x114 | 6 | (same) |
| VALU0 src0 | 270 | 0x10e | 6 | (same) |
| VALU0 src1 | 287 | 0x11f | 6 | (same) |
| VALU0 Y-enc | 282 | 0x11a | 5 | (same) |
| VALU0 2-bit pred selector | 301 | 0x12d | 2 | (same) |
| **MXU VEx0** opcode-HIGH | 62 | 0x3e | 8 | `TensorCoreVectorExtended0Encoder::Encode` @ `0x1f996940` |
| VEx0 data-format sub-disc | 57 | 0x39 | 4 | (same) |
| VEx0 MXU-id (unit) | 70 | 0x46 | 2 | (same) |
| VEx0 control (matpush target) | 54 | 0x36 | 3 | (matmul/push helpers) |
| VEx0 done-gains / latch flag | 61 | 0x3d | 1 | (same) |
| VEx0 primary operand (matmul) | 47 | 0x2f | 7 | `…MatrixMultiplyBf16` @ `0x1f99a920` |
| **MXU VEx1** opcode-HIGH | 37 | 0x25 | 8 | `TensorCoreVectorExtended1Encoder::Encode` @ `0x1f9d3800` |
| VEx1 data-format sub-disc | 32 | 0x20 | 4 | (same) |
| VEx1 MXU-id (unit) | 45 | 0x2d | 2 | (same) |
| **EUP push**(VALU 槽位 3)VALU-opcode | 194 | 0xc2 | 8 | `…VectorAlu3F32Tanh` @ `0x1f96ae40` (family) |
| EUP function selector | 183 | 0xb7 | 5 | (same) |
| EUP push src vreg | 188 | 0xbc | 6 | (same) |
| **Result 槽位** result-type discriminator | 20 | 0x14 | 2 | `TensorCoreVectorResult0Encoder::Encode` @ `0x1fa01820` |
| result dest vreg | 11 | 0x0b | 6 | (same) |
| result mode/format | 17–19 | 0x11–0x13 | 2/1 | (same) |
| `PopMxuResult` accum-mode/format | 323 | 0x143 | 8 | (same; result-opcode 7 path) |
八个 MXU source-vreg 字段在 VEx0 和 VEx1 之间**共享**(两个 MXU 从同一组 vector read port 取数),并且两个槽位逐字节相同:
| MXU systolic source-vreg(`gfc` VEx0 = VEx1) | dst_bit(十进制) | hex | width |
|---|---:|---|---:|
| src #1(proto +0x20) | 156 | 0x9c | 6 |
| src #2(proto +0x24) | 276 | 0x114 | 6 |
| src #3(proto +0x28) | 287 | 0x11f | 6 |
| src #4(proto +0x2c) | 243 | 0xf3 | 6 |
| src #5(proto +0x30) | 254 | 0xfe | 6 |
| src #6(proto +0x34) | 210 | 0xd2 | 6 |
| src #7(proto +0x38) | 221 | 0xdd | 6 |
| src #8(proto +0x3c) | 177 | 0xb1 | 6 |
> **注 — 两个 MXU control 区域是固定的 −25-bit 双生。** VEx0 的 opcode/format/MXU-id/control 区域(bits 62/57/70/54)和 VEx1 的区域(bits 37/32/45/29)恰好相差 **−25 bits**;只有八个共享 source-vreg 字段的 delta 为 0。重新实现会把两个 MXU 打包进同一个 64 字节 word:一个 control 区域写到 VEx0 偏移,第二个写到 VEx0 − 25,并共享一个 8×6-bit 操作数池。
---
## Sequencer 槽位与 20-bit 分支偏移
6acc60406 sequencer 槽位(`TensorCoreScalarAlu0Encoder::Encode` @ `0x1f87b420`)遵循 V5+ 形状:一个 `{6-bit opcode-HIGH, 5-bit opcode-LOW}` 对,加上操作数字段和 dest 字段;branch/call 目标落在 **immediate 槽位 0**,而不是 sequencer 槽位自身。
```text
gfc TensorCoreScalarAlu0 sequencer slot:
per-slot pred selector @ bit 489 (0x1e9) w2 ; 2-bit selector into the predicate pool
opcode-HIGH / family @ bit 483 (0x1e3) w6 ; = 0 for branch/call, op for ALU compute
opcode-LOW discriminator @ bit 478 (0x1de) w5 ; 4/5/6/.. (see map)
x-target / 2nd operand @ bit 472 (0x1d8) w6 ; BranchSreg / Call aux
call dest sreg @ bit 467 (0x1d3) w5 ; return-address link register
branch/call offset @ imm slot 0 = bit 423 (0x1a7) w20 ; signed −0x80000..+0x7FFFFopcode-LOW discriminator 值映射(与所有 V5+ 代共享):
| 值 | Op |
|---|---|
| 4 | BranchAbsolute |
| 5 | BranchRelative |
| 6 | CallAbsolute |
| 7 | CallRelative |
相对 Ghostlite(glc),GF 有两个 sequencer 细节,正好与下文的 predicate 变化互为对应:GF sequencer 槽位更宽,它在 bit 472 增加一个 Ghostlite 槽位没有的 6-bit 操作数字段;并且它的 predicate 字段从 Ghostlite 的 4-bit reg + 1-bit inversion 缩小为 bit 489 上的 2-bit selector。任何 V5+ 代都没有包内 delay-slot 字段;branch delay-slot count 是 bundle-packer 的 pad-count(branch 后追加空包),不是编码槽位 bit。hardware loop 同样不是编码字段:它是 sequencer opcode 读取 LCC-register,并馈入一个 conditional BranchRelative。
专用双 Predicate 槽位(GF vs Ghostlite)
这是定义这一代的结构性 predicate 变化。Viperfish 和 Ghostlite 在每个功能槽位顶部携带逐槽位 4-bit predicate register index + 1-bit inversion。6acc60406 把它拆成两个部分:
- 一个专用双 predicate 槽位(
TensorCorePredicatesEncoder::Encode@0x1f86e500),在 64 字节包最高端持有一个双条目 register 池。 - 一个逐槽位 2-bit selector(例如 sequencer 槽位上的 bit 489、VALU0 上的 bit 301),从
{pred_0, pred_1, always, never}中选择一个。
池布局逐字节来自 encoder 中四个 BitCopy 调用:
gfc TensorCorePredicatesEncoder::Encode @ 0x1f86e500:
pred_0 reg -> bit 501 (0x1f5) w4 ; mov esi,0x1f5 ; mov r8d,0x4 ; call BitCopy
pred_0 invert -> bit 505 (0x1f9) w1 ; mov esi,0x1f9 ; mov r8d,0x1
pred_1 reg -> bit 496 (0x1f0) w4 ; mov esi,0x1f0 ; mov r8d,0x4
pred_1 invert -> bit 500 (0x1f4) w1 ; mov esi,0x1f4 ; mov r8d,0x1
```text
每个 4-bit `reg` 字段索引 16 条目的 `PredicationSlot` 池(0..15)。随后,每个功能槽位只携带 2-bit selector。这就是“两个 predicate 槽位已经被占用”溢出规则的 bit 精确实现:bits 496..505 上的两个 `(reg, invert)` 条目就是每包的全部 predicate 预算。
| Predicate 模型 | Viperfish / Ghostlite | 6acc60406 |
|---|---|---|
| 逐槽位字段 | 4-bit reg + 1-bit invert(TC: reg @ 499, inv @ 503 on VXC) | 2-bit selector(TC seq @ 489) |
| 池 | 无(每个槽位自包含) | 专用 `TensorCorePredicates` 槽位 @ bits 496..505 |
| 每包 predicate 预算 | 逐槽位(无界) | 恰好两个池条目(`pred_0`、`pred_1`) |
> **陷阱 — GF 上槽位的 predicate 是间接引用,Ghostlite 上是直接索引。** Ghostlite decoder 直接从槽位读取 4-bit register index。6acc60406 decoder 必须读取槽位的 2-bit selector,然后在专用 predicate 槽位中解析到 `pred_0`/`pred_1` 池。把 GF 2-bit 字段当作 register index(而不是池 selector)会解码出错误 predicate。
---
## MXU Format 重映射与 FP8(GF vs Ghostlite)
MXU 槽位是 GF “latency/format remap” 所在的位置。槽位机制与其他 V5+ 代相同:两个 `VectorExtended` 槽位(VEx0、VEx1)对应两个 MXU,每个槽位都是通过槽位 encoder jump table 分发的、由 `BitCopy` 打包的逐 op helper。但 dtype 集、opcode bit 和 result-slot 偏移都会移动。
### Dtype 集:仅浮点,显式命名 FP8
6acc60406 支持**四种** matmul/push dtype,全部为浮点:`{F32, E4m3, Bf16, E5m2}`。它完全移除了整数 matmul 组。符号表统计是决定性的:
| Generation | PushMatrix / MatrixMultiply dtype 集 |
|---|---|
| **6acc60406(`gfc`)** | `F32`、`E4m3`、`Bf16`、`E5m2`(4 个,仅浮点;FP8 = e4m3 / e5m2) |
| Ghostlite(`glc`) | `F32`、`If8`、`Bf16`、`Bf8`(float)+ `U8`、`S8`、`U4`、`S4`(int)(8 个) |
重命名是重映射的核心:Ghostlite 把两个 FP8 格式命名为 `If8` / `Bf8`,而 6acc60406 明确命名为 **`E4m3`** 和 **`E5m2`**,并且没有注册任何整数 matmul dtype。(这里的 `e4m3`/`e5m2` 是 IEEE 风格的 FP8 mantissa/exponent 拆分;GF 对这些格式的 MXU latency/format 映射,包括 FP8 `fnuz` 处理和 result-format 重映射,详见 [GF MXU latency cost page](../cost/mxu-latency-gf.md)。)
### MXU 槽位 bit 图
```text
gfc MatrixMultiplyBf16 @ 0x1f99a920 (VEx0):
opcode-HIGH (literal 0x1) -> bit 62 (0x3e) w8 ; mov esi,0x3e ; mov r8d,0x8
data-format (literal 0x1) -> bit 57 (0x39) w4 ; bf16 = 1 (push-format enum)
control (3-bit) -> bit 54 (0x36) w3
done-gains / latch flag -> bit 61 (0x3d) w1
primary operand -> bit 47 (0x2f) w7
MXU-id (unit) -> bit 70 (0x46) w2 ; addresses up to 4 (2 used)
8 systolic source vregs -> bits 156/276/287/243/254/210/221/177 (w6 each)VEx0 encoder 的 opcode 上界是 cmp 0x54 = 85 ops/slot。weight latch 是 LoadMatrixRegister{Gmr,Lmr}{Msra,Msrb}[Bf16Conversion] opcode 家族(opcode-HIGH 0x37 @ bit 62 w8,4-bit sub-discriminator @ bit 57);moving-operand push 是 PushMatrix<fmt>[Masked](opcode-HIGH 0xe @ bit 64 w6,3-bit MatpushTarget MSRA/MSRB control @ bit 54)。融合的 latch-via-LMR matmul MatrixMultiplyLmr(sub-format 0x2)实现 K>128 多 pass accumulate(相对 Ghostlite 的专用 PopAddMxu01Result)。
Result-slot 重映射
Result 槽位(TensorCoreVectorResult0Encoder::Encode @ 0x1fa01820)是 “res-remap” 差异所在:discriminator 和 dest-vreg 字段相对 Ghostlite 下移:
| Result-slot 字段 | Ghostlite(glc) | 6acc60406(gfc) |
|---|---|---|
| result-type discriminator | bit 24 w4 | bit 20 w2 |
| dest vreg | bit 14 w6 | bit 11 w6 |
PopMxuResult accum-mode/format | (per +0x1c) | bit 323 w8 |
| result-opcode bound | 0x8 (9 ops) | 0x7 (8 ops) |
result-opcode 映射(proto 子消息 tag,从 TensorCoreVectorResult0Encoder::Encode @ 0x1fa01820 中的 switch 读取):5 = PopEupResult(EUP transcendental pop)、6 = TransposeResult、7 = PopMxuResult(matres pop;只有 case 7 分支会把 8-bit accum-mode/format 写到 bit 323)。6acc60406 没有 PopAddMxu01Result(Ghostlite 的融合 accumulate),也没有 PopCcrfResult(Viperfish 的 scalar pop):它的 result 子消息集是 {PopEupResult, TransposeResult, PopMxuResult}。
EUP / Transcendental Push(VALU 槽位 3)
Transcendental push 是一个 VALU slot-3 op(Alu3),不是 MXU op:单发射 XLU 只从 VALU 槽位 3 取源。push 写入一个 5-bit function selector,并在一个或多个包之后通过 result 槽位的 PopEupResult opcode pop。
gfc EncodeTensorCoreVectorAlu3F32Tanh @ 0x1f96ae40:
VALU opcode (EUP-push family, 0x0) -> bit 194 (0xc2) w8 ; mov esi,0xc2 ; mov r8d,0x8
EUP function selector -> bit 183 (0xb7) w5 ; mov esi,0xb7 ; mov r8d,0x5
EUP push src vreg -> bit 188 (0xbc) w6 ; mov esi,0xbc ; mov r8d,0x6
```text
5-bit function selector 值映射(由逐函数 `Alu3` helper 字面量验证):
| Function | F32 selector | Bf16 selector |
|---|---:|---:|
| `Erf` | 0x0e (14) | 0x0f (15) |
| `ReciprocalSqrt` | 0x10 (16) | 0x0c (12) |
| `PowTwo` (2^x) | 0x11 (17) | 0x19 (25) |
| `LogTwo` (log2) | 0x12 (18) | 0x1a (26) |
| `Tanh` | 0x13 (19) | 0x1b (27) |
| `ShiftedSigmoid` | 0x14 (20) | 0x1c (28) |
| `Reciprocal` | 0x15 (21) | 0x1d (29) |
| `Sinq` (sin) | 0x17 (23) | 0x1e (30) |
| `Cosq` (cos) | 0x18 (24) | 0x1f (31) |
Push-pop 协议:包 N 发射带 function selector 的 VALU3 op;包 N+k 发射 result 槽位 `PopEupResult`(result-opcode 5),dest vreg 位于 bit 11。
---
## Decode 侧:逆向双生
Codec 附带一个对称 decoder;`gfc::isa::TensorCoreVectorExtended0Decoder::Decode` @ `0x1f96d020`(以及 `…Extended1Decoder::Decode` @ `0x1f9aa7a0`)把 64 字节 span 读回 typed proto。机制是 `BitCopy` 的结构性逆过程:span 被暂存到 16 字节 struct(base 处 size-tag,base+8 处 bundle bytes),然后每个字段由一个很小的 `Field::GetConcatenatedValue` accessor 读取(`mov rax,[base+off]; shr rax,shift; and rax,mask`,其中 absolute bit = `(off−8)*8 + shift`),opcode 则通过按顺序尝试逐 dtype 的 `Opcode::Matches` mask predicate 解析(`Noop`,然后 `MatrixMultiply*`,再然后 `PushMatrix*`)。
Decode 侧独立确认了 GF MXU 布局,并固定了两个 GF 专属事实:
- **Latch opcode @ bit 64。** `gfc` `PushMatrix*Opcode::Matches` 在 bit 64 读取 latch opcode(width 6 = 14,四个 dtype 全部为 float),并在 bit 59 读取 dtype-class(width 2):`{F32=0, E4m3=1, Bf16=2, E5m2=3}`。Matmul opcode 是 bit 62 上的统一 8-bit 字段(`MatrixMultiply*Lgmr{Msra,Msrb}` @ `0x1f98f740`,值 `0x2`=Msra / `0x3`=Msrb,MSR-select = opcode LSB);latch valid-guard 是 `bt bit 62` 测试(GF 中对应 Ghostlite 的 2-bit `58,59 == 3` guard)。
- **Inter-MXU 双生在 GF 上是 −25(Ghostlite 上是 −21)。** 因为 GF 的 MXU0 control 区域比 Ghostlite 高 +4 bit(latch opcode 60→64),而 MXU1 在两代中都锚定于 bit 39,所以 GF 的 MXU0↔MXU1 delta 扩大到 −25(latch op 64→39,dtype-class 59→34,matmul op 62→37,matmul fmt 57→32)。
| MXU-twin 几何 | MXU0 latch op bit | MXU1 latch op bit | inter-MXU twin | matmul MSR-LSB (MXU0/MXU1) |
|---|---:|---:|---:|---|
| Ghostlite(`glc`) | 60 | 39 | −21 | 58 / 37 |
| **6acc60406(`gfc`)** | **64** | **39** | **−25** | **62 / 37** |
> **陷阱 —** 6acc60406 inter-MXU twin 是 **−25**,不是 Ghostlite 的 −21:`glc`→`gfc` 的 +4 MXU0 漂移(latch opcode 60→64)会叠加到 inter-MXU 偏移上,因为 MXU1 在两代中都保持锚定于 bit 39。−21 只适用于 Ghostlite。
完整的 decode 侧机制(staged-copy accessor 模型和线性 `Opcode::Matches` 分发)与 Viperfish 共享,见 [Decode-Side: VF / GXC](decode-side-vf-gxc.md)。
---
## 示例:6acc60406 包中的 bf16 `vmatmul` + `vtanh.f32`
在新建 512-bit 缓冲区中编码 MXU 0 上的 bf16 matmul(`VectorExtended` 槽位 0,未加 predicate)和一个 `tanh.f32` transcendental:
```text
EncodeBundle @ 0x1e838cc0 -> gfc TC worker @ 0x1d371540 walks each slot encoder.
VectorExtended0Encoder::Encode (the MatrixMultiplyBf16 helper):
MXU-id (0) -> bit 70 (w2)
opcode-HIGH (0x1) -> bit 62 (w8)
data-format (bf16=1) -> bit 57 (w4)
control -> bit 54 (w3) ; done-gains -> bit 61 (w1)
primary operand -> bit 47 (w7)
8 systolic src vregs -> bits 156/276/287/243/254/210/221/177 (w6 each)
VectorResult0Encoder::Encode (PopMxuResult, result-opcode 7):
result-type disc -> bit 20 (w2)
accum-mode/format -> bit 323 (w8)
dest vreg -> bit 11 (w6)
VectorAlu3 F32Tanh (EUP push):
VALU-opcode (EUP, 0x0) -> bit 194 (w8)
function selector (0x13)-> bit 183 (w5)
push src vreg -> bit 188 (w6)
... one+ bundles later: PopEupResult (result-opcode 5), dest vreg -> bit 11 (w6)空槽位保持为任何槽位填充前写入包 header 的 kNeverExecute predicate stamp(见 包模型);已填充槽位的 2-bit selector 会用池索引覆盖默认值。
交叉引用
- Ghostlite 包:本页与之对比的
glc(v4)同族页面:8-dtype MXU 集、逐槽位 4+1 predicate、bits 14/24 上的 result 槽位、−21 inter-MXU twin。 - 包模型:VLIW 发射 word 模型、64 字节宽度家族、空槽位
kNeverExecute约定。 - Decode-Side: VF / GXC:staged-copy
GetConcatenatedValue/Opcode::Matchesdecode 机制,以及逐代 MXU twin 几何。 - GXC 家族:为什么 6acc60406 =
gfc(general fetch-core),并且共享 VXC HAL 但拥有自己的 ISA。 - 代号矩阵:
TpuVersionenum、匿名 case-5 codec,以及6acc60406↔TPU7x映射。 - MXU Latency: GF (6acc60406):GF 专属逐格式 MXU latency / reservation 矩阵、FP8
e4m3/e5m2(fnuz)处理和 result-format 重映射。