Skip to content

TAC 引擎

本页中的每个地址、位偏移以及按代际划分的存在性声明,都是从 libtpu-0.0.40-cp314 wheel(BuildID md5 89edbbe81c5b328a958fe628a9f2207d)里的 libtpu.so 按字节精确读取的,来源包括反混淆后的 C++ 符号表、嵌入的 proto 描述符字符串,以及反编译得到的逐槽 Encoder::Encode 函数体。其他版本会有所不同。

摘要

TAC,即 Tile Access CoreTpuSequencerType = 4,是 SparseCore 的 SCS / TAC / TEC 三引擎组合中的第三个成员。尽管它的 bundle 很宽,但能力范围最窄。SCS 是标量控制定序器,TEC 是宽向量引擎,而 TAC 是一个纯地址计算 + tile-fetch DMA 发起器:它接收一串 embedding 索引(由 SCS 产生,或由另一个 SC 的 stream 槽产生),并发出 gather DMA,把 embedding 行从 HBM/SPMEM 拉到每个 tile 的工作 SRAM(TILE_SPMEM)中,随后 TEC 在这些数据上计算。它有自己的定序器线程,包括分支、halt、delay、整数/地址算术、比较、谓词生成、用于地址暂存的 SMEM load/store、sync/atomic 协调以及一个 stream 槽,但没有 FPU 向量路径、没有向量 ALU、没有向量 load/store、没有 scan/sort/uniquify。在 embedding 流水线中,它位于“我需要哪些行”和“这些行现在已经在 tile SRAM 中”之间。

关于 TAC,最重要的事实是它并非存在于每一代。SparseCore 首次出现在 Viperfish(TPU v5p)上,采用 SCS+TAC+TEC 三引擎拆分;Ghostlite(TPU v6e)保留全部三个引擎;6acc60406 代(TPU v7x)完全移除了 TAC,把它的 tile-fetch 发起职责折叠进 SCS+TEC 组合中(SCS 计算 gather 地址,TEC 自己的 stream 槽发起 DMA)。这是直接的二进制读数,不是推断:6acc60406gxc.gfc)命名空间中有零个 SparseCoreTac* 符号,也有零个 SparseCoreTac* 反编译函数;相比之下,Viperfish(vxc.vfc)和 Ghostlite(gxc.glc)各有约 930–950 个。为 6acc60406 目标发出 TAC 程序的重实现,会产生 codec 无法编码的东西。

TAC bundle 是 64 字节(512 位)的 VLIW word,物理宽度与 TEC bundle 相同,但它复用了 SCS bundle 的低位区域槽布局,并让高 320 位保持未写入。它把宽度花在许多并发的标量风格地址操作上,而不是向量计算上。本页记录该引擎的 codec/template 身份、64 字节 bundle 及其槽基地址的字节/位偏移(从每个逐槽 Encoder::Encode 内部的 BitCopy 目标立即数恢复)、它执行的操作清单(即 SCS 标量/stream 集合,并限制为地址子集),以及按代际划分的存在性和确认 6acc60406 = 0 的反编译计数。

对重实现而言,契约是:

  • TAC 是 TpuSequencerType = 4,并且是独立的 codec。 它由 SparseCoreTacCodecBase<…, TpuSequencerType=4>LN3tpu16TpuSequencerTypeE4E template 字面量)编码,只存在于 vxc.vfcgxc.glc 下。dispatcher 会把同一个 absl::Span<uchar> 缓冲区交给每个逐槽 encoder,所以每个槽都写入绝对 bundle 位偏移。
  • 64 字节 bundle 只使用 bits 3..191,也就是 SCS 低位区域(4×20 位立即数、vector-scalar bridge、scalar-misc 槽、两个 scalar-ALU lane,以及 Dma/Stream oneof-of-lane),另加 Stream 槽写入的两个 header 控制位(@3/3 和 @6/1)。512 位 bundle 的高 320 位不承载任何内容;TAC 没有向量槽需要填充。
  • 操作集合是 SCS 标量 + stream 集合,而不是单独的 enum。 TAC 复用 SparseCoreScalarAlu / SparseCoreScalarMisc / SparseCoreStream proto-enum 空间;合法性在 emit 期间由 SparseCoreTacScalarAlu{0,1}Encoder / SparseCoreTacStreamEncoder 类内部限制。不存在可枚举的 SparseCoreTacScalarAlu proto enum。
  • 按代际存在性是契约的一部分。 Viperfish(v5p)和 Ghostlite(v6e)提供 TAC;6acc60406(v7x)没有。应把这编码为强 codec-family 测试,而不是 flag。
引擎TAC — Tile Access Core(地址计算 + tile-fetch DMA 发起器)
定序器 enumtpu::TpuSequencerType = 4 (TPU_SEQUENCER_TYPE_SPARSE_CORE_TILE_ACCESS_CORE_SEQUENCER)
Codec 根SparseCoreTacCodecBase<…, TpuSequencerType=4>(位于 asic_sw::deepsea::{vxc.vfc, gxc.glc}::isa
Bundle 大小64 字节 / 512 位(BundleSizeBytes → codec-metadata vtable 槽 6)— 没有 check trailer
活动区域bits 3..191(SCS 低位区域;Stream 槽还会写 header bits @3/3 和 @6/1);bits 192..511 未写入
槽清单4×20 位立即数 · vector-scalar bridge · ScalarMisc · TacScalarAlu1 · TacScalarAlu0 · Dma / TacStream(lane 的 oneof)
操作集合SCS SparseCoreScalarAlu / SparseCoreScalarMisc / SparseCoreStream enum,地址子集
计算路径无 — 没有向量 ALU、没有向量 load/store、没有 scan/sort/uniquify
存在于Viperfish / v5p (vxc.vfc) · Ghostlite / v6e (gxc.glc) — 不存在于 6acc60406 / v7x (gxc.gfc)
置信度CONFIRMED(反编译 / BitCopy 立即数锚定),除非某行或标注另有说明

Codec 和定序器身份

用途

TAC 与 SCS 和 TEC 一样,由其 codec 上作为非类型模板参数携带的 tpu::TpuSequencerType 值选择。操作级别没有任何东西命名引擎;引擎分配由包围的 outlined function 上标记的 sc.sequencer 字符串属性("access")决定(见 Region → Sequencer Outliner),而下游读回的 codec template enum(4)会选择此 codec。

入口点

text
TpuSequencerType = 4  (TILE_ACCESS_CORE_SEQUENCER)
  └─ SparseCoreTacCodecBase<SparseCoreTacBundle, TacScalarSubBundle,
        SparseCoreTacScalarAlu0{Decoder,Encoder},
        SparseCoreTacScalarAlu1{Decoder,Encoder},
        SparseCoreScalarMisc{Decoder,Encoder},
        SparseCoreTacStream{Decoder,Encoder},
        SparseCoreDma{Decoder,Encoder},
        SparseCoreVectorScalar{Encoder,Decoder},
        SparseCoreScalarImmediates{Decoder,Encoder},
        …, SparseCoreTacProgram, TpuSequencerType=4>
       ├─ Encoder<…>::EncodeBundle   ── alloc 64 B, memset 0, dispatch each slot encoder
       │    └─ each <Slot>Encoder::Encode(this, Message, absl::Span<uchar> buf)  ── SAME buf to all
       │         └─ BitCopy(dst=buf, esi=dst_bitoff, src, src_bitoff, r8d=nbits)  ── LE bit packer
       └─ Encoder<…>::BundleSizeBytes ── codec_metadata.vtable[+0x30]()  → 64
```text

### Codec 模板参数列表

被混淆的 `SparseCoreTacCodecBase` 模板名本身就是 sub-bundle 清单;该 codec 精确枚举它必须驱动的槽 {Encoder,Decoder} 对。它从反混淆符号恢复而来(`…ELN3tpu16TpuSequencerTypeE4EE…` 后缀固定了整数字面量 `4` = TAC 定序器类型 enum 值):

| 槽 {Enc,Dec} 类 | 角色 | 它消费的 op-enum |
|---|---|---|
| `TacScalarSubBundle` | 两个标量 lane 的 wrapper |(结构性)|
| `SparseCoreTacScalarAlu0` | 标量/地址 ALU lane 0(TAC 变体) | `SparseCoreScalarAlu` |
| `SparseCoreTacScalarAlu1` | 标量/地址 ALU lane 1(TAC 变体) | `SparseCoreScalarAlu` |
| `SparseCoreScalarMisc` | scalar misc / sync / atomic 槽(与 SCS 共享) | `SparseCoreScalarMisc` |
| `SparseCoreTacStream` | stream 槽,即 tile-fetch DMA 发起器(TAC 变体) | `SparseCoreStream` |
| `SparseCoreDma` | DMA 发起槽(与 SCS 共享) | `SparseCoreDma` |
| `SparseCoreVectorScalar` | scalar→vector 值桥接槽(共享) | `SparseCoreVectorScalar` |
| `SparseCoreScalarImmediates` | 4× immediate-value 槽(共享) | `SparseCoreImmediates` |

> **NOTE — TAC 不声明任何向量槽。** 将此列表与 [TEC](tec-engine.md) codec 对比,后者还携带 `SparseCoreTecVectorAlu0/1/2`、`…VectorLoad`、`…VectorStore`、`…VectorExtended` 和 `…VectorResult`。TAC 模板中*没有*这些槽。该引擎在结构上是第二个带 stream 槽的标量定序器;它唯一“宽”的属性是 64 字节 bundle,而这个宽度承载的是许多并发的标量地址操作,不是向量计算。

### Bundle 大小 — `BundleSizeBytes`

`Encoder<…>::BundleSizeBytes` 读取 codec metadata 的槽 6(`vtable[+0x30]`)。对于 Viperfish(`EncoderVfSparseCoreTac::BundleSizeBytes` @ `0x1d2eebe0`),它尾调用 `codec_metadata.vtable[+48]()`;metadata 函数体证明了该值:

```c
function ViperfishCodecMetadata_BundleSizeBytesForHbm(this, seq):   // 0x1ee71380
    result = 32                                  // seq == 3 (SCS)
    if seq != 3:
        result = 64                              // TAC or TEC
        if (seq & 0xFFFFFFFE) != 4:              // seq not in {4,5} → FATAL
            LOG(FATAL) << "Unhandled component"  // codec_metadata_viperfish.cc:31
    return result

(seq & 0xFFFFFFFE) != 4 掩码是按字节精确的来源:它只允许 seq ∈ {4, 5}(TAC、TEC)进入 64 字节分支,并让 seq == 3(SCS)进入 32 字节分支;其他任何值都是 fatal。因此 TAC(seq 4)= 64 字节,与 TEC 相同,不同于 32 字节的 SCS。与所有 SC bundle 一样,这里没有 0x55 check trailer(全零 bundle 表示“所有槽 inactive”)。

QUIRK — TAC 是唯一一个 64 字节宽但不承载计算的 SC 引擎。 如果重实现者从“它是不是 64 字节 bundle?”来确定缓冲区大小,就会因为假定存在并不存在的向量能力而过度配置 tile-fetch 程序。这个宽度用于标量地址操作并行性,也就是在一个 cycle 中执行多个独立的 index/stride/offset 计算并发起 DMA,而不是用于 64 字节 TEC bundle 所使用的向量槽。


TAC Bundle 槽基址图

用途

每个 TAC 槽 encoder 都从 dispatcher 接收同一个输出缓冲区 span,因此每个 BitCopy(dst, esi, …) 都写入一个绝对 bundle 位偏移。所以每个字段的目标位基址和宽度,就是每次 call BitCopy 之前的 mov esi,IMM / mov r8d,IMM 对。下图从 Ghostlite(gxc.glc)逐槽 encoder 恢复;Viperfish(vxc.vfc)按字节相同。Bundle = 64 字节 / 512 位;活动区域是 SCS 低位区域(标量/立即数栈位于 bits 7..191,Stream 槽另外写入两个 header 控制位 @3/3 和 @6/1),并且 bits 192..511 未写入

槽图

baseendwidthopcode bit内部模板
(header)067bundle prefix — 只有 Stream 槽在这里写入(@3/3、@6/1);其他槽让其保持零
ScalarImmediates786804 × 20-bit(@7、@27、@47、@67)
VectorScalar8711024scalar→vector bridge
ScalarMisc1111372712727 位标量模板
TacScalarAlu1 (lane 1)1381642715427 位标量模板
TacScalarAlu0 (lane 0)1651912718127 位标量模板
Dma (oneof of lane)87191181 / 154标量 opcode + payload @87..142
TacStream (oneof of lane)3191181 / 154标量 opcode + payload @99..162,另有 header bits @3/3 和 @6/1
(reserved / pad)192511320未写入 — 无向量路径

三个标量槽(Misc @111、Alu1 @138、Alu0 @165)在 vector-scalar bridge 上方以 27 位间隔堆叠,与 SCS bundle 完全相同。这就是同一个低位区域布局TacScalarAlu0 opcode @181、TacScalarAlu1 @154、ScalarMisc @127,与 SCS 的位位置相同。DMA 和 TacStream 槽不是单独的物理区域:它们是标量 lane 的 oneof alternatives(该 lane 承载 ALU op 或 Misc op 或 Dma op 或 Stream op),所以 Dma/Stream op 会把它的 opcode 写入标量 lane 的 opcode 字段(lane 0 为 @181,lane 1 为 @154),并借用较低的 bundle payload 来放置多字 descriptor。

27 位标量模板

每个标量槽的内部布局(slot-relative)如下,按位精确来自 TacScalarAlu0 @165;TacScalarAlu1 @138 和 ScalarMisc @111 的布局相同,只是整体 −27:

字段offsetwidth含义
operand x0+05标量寄存器选择器
ScalarY+56标量寄存器或立即数选择器
operand x1+115标量寄存器选择器
OPCODE+166≤ 64 个标量 op
normal_predication+223SparsecoreNormalPredication
rotate_predication+224is_rotate 时重叠(16-entry ring)
predication_inversion+251
is_rotate_predication+261

反编译交叉检查 — BitCopy 立即数

TacScalarAlu0Encoder::Encode(Ghostlite @ 0x1ea17e40)接收一个 SparseCoreScalarAlu message 和 bundle span;它的前导代码及各形式的 BitCopy 调用固定了每个偏移:

c
function TacScalarAlu0Encoder_Encode(this, msg /*SparseCoreScalarAlu*/, buf):  // 0x1ea17e40
    BitCopy(buf, 187, &msg[+32], 0, 4)        // rotate_predication header @187/4  (= slot-base 165 +22)
    BitCopy(buf, 191, &msg[+24], 0, 1)        // is_rotate / inversion bit  @191/1 (= +26)
    switch (msg.opcode /* [+80] = the SCS ScalarAlu proto-enum TAG, not the wire opcode */):
      case 0: return 1                         // NoInstruction — leave slot empty
      case 6:  BitCopy(buf, 181, 0,    6)      // 6-bit HW OPCODE @181 := 0 (tag 6 → wire op 0)
               BitCopy(buf, 176, 0,   5) …     // operand x1 / sub-selector region @176/5 (= +11)
      case 7:  BitCopy(buf, 181, 0,    6)      // 6-bit HW OPCODE @181 := 0 (tag 7 = Delay)
               BitCopy(buf, 176, 3,    5)       // sub-selector := 3
               BitCopy(buf, 165, …,  11) …     // operand x0 / ScalarY  @165 (= slot base)
      case 8:  BitCopy(buf, 181, 0,6); BitCopy(buf,176,8,5); BitCopy(buf,165,1,5)  // tag 8 = SetTag
               BitCopy(buf, 170, …,   6) …     // ScalarY @170/6  (= +5)
      … case 0x0A..0x5B: tail-call EncodeSparseCoreTacScalarAlu0<Op>(buf)  // ~70 named proto tags
      default: return MakeErrorImpl("Cannot find matching encoder for instruction: …")
```text

`TacScalarAlu1Encoder::Encode`(@ `0x1ea2a7a0`)是同一函数体下移一个 lane:OPCODE @154/6,operand-x1 区域 @149/5,槽基址 @138,谓词 header @160/4 + @164/1。`TacStreamEncoder::Encode`(@ `0x1ea338e0`)写入 OPCODE @181/6,并把它的 descriptor 分布在 bits 99..162(off-tile/indirect operand @105/5、@110/1、@104/1、@99/5;sync/list controls @154/1、@155/1、@156/1、@157/3、@160/1、@161/1;stream-opcode mirror @162/6),使用同样的 @187/4 + @191/1 谓词 header,并且作为 TAC 槽中唯一的例外,它还写入两个 **header 控制位 @3/3 和 @6/1**(在反编译中由 `BitCopy(a3, 3, …, 0, 3)` 和 `BitCopy(a3, 6, …, 0, 1)` 验证)。这些 header 位是 TAC 中 bit 87 以下唯一的写入;其他每个槽都从 bit 87 或更高处开始。

> **CONFIRMED — 没有 TAC 槽 encoder 写入 192 或更高的 bit。** 扫描 `TacScalarAlu0`(@1ea17e40)、`TacScalarAlu1`(@1ea2a7a0)、`TacStream`(@1ea338e0)以及共享的 `SparseCoreDmaEncoder`(@1ea09b40)里的 `BitCopy` 目标立即数后,任何 TAC 槽写入的最高目标位是 **191**(标量 lane 0 的 is-rotate 位),最低是 **3**(Stream 槽的 header 控制字段)。512 位 TAC bundle 的高 320 位是纯 padding,这是 TAC 没有向量路径并且只复用 SCS 低位区域加两个 stream-header 位的直接字节级证据。
>
> **GOTCHA — 槽 opcode 是共享的,槽含义按引擎决定。** `TacScalarAlu0` 的 opcode @181 占据与 SCS `ScalarAlu0` 的 opcode @181 *相同*的位字段,并且两者消费*相同*的 `SparseCoreScalarAlu` proto enum。重实现者无法仅从 bundle 位判断 SCS-vs-TAC;引擎由包围函数上的 `sc.sequencer` 属性(`"scs"` vs `"access"`)固定,并读回以选择 codec。bundle 与引擎无关;codec 选择不是。

---

## 操作清单

### 用途

TAC 执行 SCS 标量指令集的地址和控制子集,以及 stream 槽;它的全部职责就是计算 gather 地址并发起 tile-fetch DMA。它不携带单独的 opcode enum;它复用 SCS 的 `SparseCoreScalarAlu`、`SparseCoreScalarMisc` 和 `SparseCoreStream` proto-enum 空间,并在 emit 时由 `SparseCoreTac*Encoder` 类限制合法性。

### 操作类别

以下类别来自 `TacScalarAlu0Encoder::Encode` switch(`SparseCoreScalarAlu` proto-enum tags 0x06..0x5B,位于 `msg[+80]`)以及共享的 `SparseCoreScalarMisc` / `SparseCoreStream` / `SparseCoreDma` encoder。这些是 TAC 变体接受的 SCS 标量/stream op。下面括号中的十六进制值是 **proto-enum tag**switch 判别值),不是发往 bundle bits @1816 位 wire opcode;逐 op 的 `Encode<Op>` helper 会把每个 tag 重新编码为 6 位 OPCODE 字段外加 @176 的 sub-selector,因此多个 proto tag 可以共享 wire opcode `0`(例如上面的 tags 6/7/8):

| 类别 | 在 TAC 中? | 代表性 op(来自 encoder switch|
|---|:---:|---|
| 控制流和分支 | Y | `BranchAbsolute` (0x4B), `BranchRelative` (0x4C), `BranchSreg` (0x4D), `BranchAbsoluteClearIbuf` (0x5B), `CallAbsolute/Relative/Sreg` (0x4E0x50), `Delay` (0x07), `Halt` |
| 整数 / 地址 ALU(32 位) | Y | `IntegerAdd` (0x12), `IntegerSubtractYX` (0x14), `Multiply32BitIntegers` (0x52), `DivideWithRemainder*` (0x540x56), `BitwiseAnd/Or/Xor` (0x160x18), shifts (0x190x1C), `CountLeadingZeros` (0x22) |
| 比较 / 条件 | Y | `CompareInteger{Eq,Ne}` (0x2D0x2E), `CompareSignedInteger*` (0x2F0x32), `CompareUnsignedInteger*` (0x330x36), `CarryOutFromIntegerUnsigned` (0x37) |
| 谓词 | Y | `PredicateOr` (0x38) |
| 寄存器文件读取 | Y | `ReadRegisterSparseCoreId` (0x41), `ReadRegisterTileid` (0x42), `ReadRegisterTaskBitmap` (0x43), `ReadRegister{Gtc,Lcc}*`, `ReadRegisterTag/Tracemark`, `ReadRegisterDifDepthRegister` (0x45) |
| SMEM load/store(地址暂存) | Y | `ScalarLoadSmem*` / `ScalarStore*Smem*` / `ScalarLoadCircularBuffer`(共享 SCS 集合) |
| 可编程资源 | Y | `SetPrefetchDepth` (0x47), `SetIndirectFilterValue` (0x48) |
| Stack / pop | Y | `PopDrf` (0x3A), `PopRcmf` (0x3B) |
| Fence / sync | Y | `ScalarFence` (0x3C), `ScalarFenceScmf` (0x3D), `ScalarFenceStream{Spmem,Hbm}` (0x3E0x3F), `ScalarFenceSelect` (0x40) |
| Misc / sync / atomic(ScalarMisc 槽) | Y | sync-flag + atomic-remote/tile 家族(`SparseCoreScalarMisc` enum,opcode @127|
| **Stream — TAC 的主要工作** | Y | `TacStream`: `IndirectStream`, `IndirectVregStream`, `LinearStream`, `StridedStream` → tile-fetch DMA |
| DMA 发起 | Y | `SparseCoreDma`: `SimpleDma`, `SingleStridedDma`, `GeneralDma`(opcode @181|
| 标量浮点 | partial | `MaxOfTwoFloatingPointValues` (0x1D), `MinOfTwoFloatingPointValues` (0x1E), `CompareFloatingPoint*` (0x250x2A), `FloatingPointMultiply` (0x51), `Convert{Int32ToFloat32,Float32ToInt32}` (0x100x11), `IsInfOrNan` (0x2B) 出现在 switch|
| 向量 ALU / load / store / scan / sort | **N** | 没有对应槽 — codec 模板不携带向量 encoder |

> **NOTE — TAC 有标量 float op,但没有向量计算路径。** 反编译的 `TacScalarAlu0Encoder::Encode` switch 包含标量浮点 opcode case:float min/max(0x1D/0x1E)、float compare(0x250x2A)、`FloatingPointMultiply`(0x51)以及 intfloat convert(0x10/0x11),编码方式与整数 ALU op 相同。精确表述是:TAC **没有*向量* FPU,也没有向量计算路径**(没有 `VectorAlu`/`VectorLoad`/`VectorStore`/`VectorExtended` 槽)。硬件是否执行这些标量 float 形式,还是 encoder enum 只是接受它们,尚未确定(MEDIUM);每个*向量*槽都不存在这一点是字节精确的(CONFIRMED)。

### Tile-Fetch 角色

TacStream 槽是该引擎的操作核心。前向 embedding 流水线运行方式是:SCS 调度 tile-fetch 程序并计算 gather descriptor;**TAC 发起 stream-gather DMA** `HBM[table_base + index_i · row_stride] → TILE_SPMEM`;TEC 对驻留的 tile 执行 vector-load 并运行逐样本 reduction。TAC 是 SCS 定序器与 TEC 向量核心之间的专用地址处理器 + DMA 发起器,在架构上类似于 Pufferfish BarnaCore address-handler 相对 BarnaCore 的角色(见 [BarnaCore Overview](../barnacore/overview.md))。`STREAM_OPCODE_*` 集合和 gather/scatter descriptor 格式归 [Stream Gather/Scatter](stream-gather-scatter.md) 所有;TAC 与 SCS 共享的 scalar/misc opcode 清单归 [Scalar Opcode Enum](scalar-opcode-enum.md) 所有。

---

## 按代际存在性

### 用途

重实现者关于 TAC 必须编码的最重要事实,是*它何时存在*。SparseCore 是 v5+ 特性;在携带 SC 的代际中,TAC 存在于 Viperfish(v5p)和 Ghostlite(v6e),并在 `6acc60406`(v7x)上被移除。判别器是 codec class family;每个代号 family namespace 下是否存在 `SparseCoreTacCodecBase`,是直接的二进制读数。

### 清单表

| Gen | Codename | Family ns | TAC present | Tile-fetch issuer | Notes |
|---|---|:---:|:---:|---|---|
| TPU v5p | Viperfish | `vxc.vfc` | **Y** | TAC stream | 第一代三引擎拆分 |
| TPU v6e | Ghostlite | `gxc.glc` | **Y** | TAC stream | 完整 SCS+TAC+TEC |
| TPU v7x | `6acc60406` | `gxc.gfc` | **** | TEC stream | **TAC removed** — 折叠进 SCS+TEC |
| earlier | Jellyfish / Dragonfish / Pufferfish | `jxc` / `pxc.pfc` ||(无 SparseCore)| BarnaCore 时代 |

### 反编译交叉检查 — `6acc60406` TAC = 0

该清单直接对反编译函数集合和符号表确认。两个独立计数中,`6acc60406` 列均为零:

| 指标 | Viperfish (`vxc.vfc`) | Ghostlite (`gxc.glc`) | `6acc60406` (`gxc.gfc`) |
|---|---:|---:|---:|
| 反混淆后的 `<ns>::isa::SparseCoreTac*` 符号(`nm -C`) | 838 | 860 | **0** |
| 文件名中名为 `SparseCoreTac*` 的反编译函数 | 932 | 952 | **0** |

`gfc`(`6acc60406`)命名空间中有**零个** `SparseCoreTac*` 反编译函数和零个 `SparseCoreTac*` 符号,而 Viperfish 和 Ghostlite 各有约 840950 个(两种计数方式不同,是因为单个反编译函数文件可以多次携带该符号,而 `nm` 计数按符号计算)。不存在 `gxc.gfc` `SparseCoreTacCodecBase` 类,不存在 `SparseCoreTacScalarAlu*Encoder`,不存在 `SparseCoreTacStreamEncoder`,也不存在 `SparseCoreTacProgram` proto。对应的 `SparseCoreTacGFSchedModelSchedClasses` LLVM 表也不存在;只有 `SparseCoreTacVF*`/`SparseCoreTacGL*` sched model,而 SCS 和 TEC 都携带 `VF`/`GL`/`GF` 三元组。TAC 已从 `6acc60406` 硅片中完全消失。

> **CONFIRMED — `6acc60406` 将 3 引擎流水线压缩为 2 个。** 在 Viperfish/Ghostlite 上,路径是 SCS → TAC(tile-fetch DMA)→ TEC(compute)。在 `6acc60406` 上,TAC 消失:TEC 自己的 stream 槽(`IndirectStream` / `IndirectVregStream` / `LinearStream` / `StridedStream`)吸收地址生成 + DMA 发起职责,SCS 计算 gather 地址(由 TEC 通过 `tile_wait_scs_smem` 消费),而新的 SCS op `BranchRelativeRotatingPreg` / `SetRotatingPredicateRegister` 以及 TEC 的 `TileSpmemLoadCircularBufferPostUpdate` 支持内层循环 tile-fetch dispatch,此前它需要 TAC 的单独定序器。结果是单个 SCS↔TEC 边界、更低硅面积以及更低延迟的 tile-fetch,代价是 TEC bundle 更重,因为它现在同时发起计算和 DMA。

### Outliner — “access” 函数来自哪里

引擎分配是字符串属性,不是 op 上的数值 enum。`TileTaskOutliningPass` 遍历每个 `sc_tpu.tile_task` op,把 body outline 成一个 `func.func`,并标记 `sc.sequencer`。在 `6acc60406` 上,它只为 tile body 标记 `"execute"`(TEC),并为包围的控制程序标记 `"scs"`;没有 `"access"`。在 Viperfish/Ghostlite 上,同一个按 Target 参数化的 pass 会额外生成 `"access"`(TAC)函数。`"access"` 值字符串以及把它映射到 `TpuSequencerType=4` 的读回谓词都位于 outliner 中;在携带 TAC 的代际上,精确的逐 op Access-vs-Execute 拆分规则没有被穷尽位追踪(`GetTransferKind` 的 `kStream`/`kDma` 结果以及 op 数据依赖会输入该规则)。见 [Region → Sequencer Outliner](region-to-sequencer-outliner.md) 和 [getSequencerType](getsequencertype.md)。

> **QUIRK — C++ `TpuSequencerType` enum 在 codec 和 geometry 之间共享;只有 *proto* enum 不同。** 本页和 SC-ISA 页面使用 C++ `TpuSequencerType` 编号 `{3 = SCS, 4 = TAC, 5 = TEC}`(codec 模板中携带的字面量;`…E4E` = TAC,已在混淆后的 `SparseCoreTacCodecBase` 符号中验证)。硬件 geometry descriptor [`SparseCoreTarget`](architecture.md#the-sparsecoretarget-map-target0x948) 由 `tpu::TpuCoreParts` 支撑,它是一个 `EnumMap<TpuSequencerType, Sequencer, 6>`(6-slot array,`TpuCoreParts` ctor @ `0x20b29e40`),并按这个**相同** C++ enum 索引 core-parts:[architecture page](architecture.md) 把逐芯片 tile 数读作 `SequencerCount(seq-type 5 = TEC)`,与 codec 编号一致。因此重实现者可以统一用 `{3,4,5}` 进行 codec 选择** `TpuCoreParts` 查找。唯一的 off-by-one 是 **protobuf** enum `TpuSequencerTypeProto`(`{4 = SCS, 5 = TAC, 6 = TEC}`,其中 `INVALID=0`),`TpuSequencerTypeFromProto` 在任何内存内使用之前都会执行 subtract-one 转换为 C++ enum;见 [getSequencerType](getsequencertype.md)。

---

## 相关组件

| 名称 | 关系 |
|---|---|
| `SparseCoreTacCodecBase<…, TpuSequencerType=4>` | TAC codec — 驱动每个 TAC 槽 encoder(仅 VF/GL) |
| `TacScalarAlu0Encoder::Encode` (`0x1ea17e40` glc) | 标量 lane-0 槽 encoder;opcode @181,`BitCopy` 立即数来源 |
| `TacStreamEncoder::Encode` (`0x1ea338e0` glc) | tile-fetch DMA 发起器槽 encoder;opcode @181,payload @99..162 |
| `ViperfishCodecMetadata::BundleSizeBytesForHbm` (`0x1ee71380`) | 证明 TAC(seq 4= 64 字节 |
| `TileTaskOutliningPass` | 在 VF/GL outlined function 上标记 `sc.sequencer = "access"`(TAC) |
| `SparseCoreScalarMiscEncoder` (`0x1ea46f00` glc) / `SparseCoreDmaEncoder` (`0x1ea09b40` glc) | TAC 与 SCS 按字节相同共享的槽 |

## 交叉引用

- [SparseCore Overview](overview.md) — Part IX 的导航入口;引擎名称、按代际存在性和数据路径。
- [SparseCore Hardware Architecture](architecture.md) — engine→core 布局、四层内存模型和 geometry-descriptor enum 偏移。
- [SCS (Scalar) Engine](scs-engine.md) — 标量控制定序器;TAC 复用其低位区域 bundle 布局。
- [TEC (Vector) Engine](tec-engine.md) — 宽向量引擎,消费 TAC 拉取的 tile,并在 `6acc60406` 上吸收 TAC 的角色。
- [Per-Engine Bundle Slot-Base Map](bundle-slot-base-map.md) — 完整的 SCS/TAC/TEC 槽基址分区,本页从中抽取 TAC 列。
- [Region → Sequencer Outliner](region-to-sequencer-outliner.md) — 标记 `sc.sequencer = "access"` 以把函数分配给 TAC 的 pass。
- [getSequencerType](getsequencertype.md) — SCS/TAC/TEC 引擎选择 accessor 和 `TpuSequencerType` enum
- [Scalar Opcode Enum](scalar-opcode-enum.md) — `SparseCoreScalarAlu` / `SparseCoreScalarMisc` 清单;TAC 将其限制到地址子集。
- [Stream Gather/Scatter](stream-gather-scatter.md) — `STREAM_OPCODE_*` 集合和 TacStream 发出的 gather/scatter descriptor。
- [SC Backend Pipeline](sc-backend-pipeline.md) — SC-MLO offload pass pipeline,用于 outline 并 lower 每引擎 bundle stream。
- [SC EmitX Dispatcher](sc-emitx-dispatcher.md) — seq3/seq4/seq5 → EmitX jump table,路由到每引擎 codec。
- [BarnaCore Overview](../barnacore/overview.md) — 已退役的 embedding accelerator;TAC 映射其 address-handler。
- **二进制:** `extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so`(build-id `89edbbe81c5b328a958fe628a9f2207d`)
- **索引条目:** Part IX — SparseCore & BarnaCore / SparseCore engines — [返回索引](../index.md)