Skip to content

立即数槽

本页中的每个宽度、位位置、proto 偏移和地址都逐字节精确地读取自 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(BuildID md5 89edbbe81c5b328a958fe628a9f2207d,未 stripped,包含完整 C++ 符号)。所有地址都是虚拟地址;.text / .rodata / .lrodata 以 1:1 映射(VA == file offset)。其他 wheel 版本会不同。

摘要

TPU VLIW bundle 没有内联立即数操作数。指令需要的每个字面量——分支/调用目标、sync-flag id 或阈值、vector-ALU 常量、DMA 段大小——都会写入一小组固定的立即数槽之一;这些槽位于 bundle word 的专用区域中,并在 bundle 的所有 slot 之间共享。slot encoder 从不在自己的 bit window 中嵌入常量;它把值路由到一个立即数槽索引,然后由单个按代区分的 encoder 把该索引写入该代固定的绝对 bit。本页把立即数槽池作为重实现目标来记录:每代的槽数量和宽度、逐字节精确的 bit 梯形表、值如何被选择并拆分到槽中、sequencer 的 20-bit 分支目标如何到达 immediate slot 0,以及 overlay-fetch DMA descriptor 如何消耗一个 immediate sync-flag。

立即数区域是 bundle 中最常被误读的一块,因为它不在任何 functional slot 内。三个事实让它变得可处理。(1) slot 宽度是一个 subtarget virtual,即 vtable slot +0x340 处的 TPUSubtarget::getImmediateSizeInBits():BarnaCore (v4) 路径为 16 bits,每个 V5+ generation(Viperfish / Ghostlite / 6acc60406)为 20 bits。(2) slot 位位置是一个平坦的 (absolute-bit, width) 对列表,由 <gen>ImmediatesEncoder::Encode 通过通用 packer BitCopy(dst, dst_bit, src, src_bit, nbits) (0x1fa0a900) 写入,因此 immediate slot i 的位置就是第 iBitCopy 调用的字面量 dst_bit 参数。(3) 一个值落入哪个 immediate slot 由上游运行时 ResourceSolver slot-pool walk(getFullImmediate @ 0x13be79a0)决定,而不是由静态的 per-encoding 表决定;宽于一个 slot 的值会被拆成 lo/hi 两半跨两个 slot 存放。

对重实现而言,约定如下:

  • 每代 immediate-slot 宽度getImmediateSizeInBits()(vtable +0x340):BarnaCore = 16,Viperfish/Ghostlite/6acc60406 = 20。同一宽度同时支配 getPackedImm 中的 value-fit test,以及 getFullImmediate 中的 lo/hi 拆分。
  • TensorCore(64-byte V5+)bundle 有 6 个 immediate slots,由 TensorCoreImmediatesEncoder::Encode 从 proto fields +0x18 + 4*i(i = 0..5)写入。基础梯形表是 Viperfish 430/410/390/370/350/330(stride −20);Ghostlite 是该梯形表 +3,6acc60406 是该梯形表 −7
  • SparseCore(32-byte)bundle 有 4 个 immediate slots,所有 V5+ gens 上位置为 67/47/27/7;Ghostlite 的 SCS encoder 为 6-slot wide variant 额外添加两个(215/195)。
  • Jellyfish(41-byte)和 Pufferfish(51-byte)bundle 各自携带 6 个 16-bit immediate slots;Pufferfish 将它们放在 shared operand pool 的 256/272/288/304/320/338,Jellyfish 将它们作为 proto fields +0x68..+0x7C 携带。这些 pre-V5 codecs 不是 subtarget-virtual。
  • 值 ≤ width 占用一个 slot;更宽的值会拆分为 low half 和 high half 跨两个 slots,由 getFullImmediate 记录为 SmallVector<pair<slot_id, ImmediateSlot>, 4>
  • sequencer 的 signed 20-bit branch/call target 落在 immediate slot 0——也就是 barrier/sync ops 复用来存放 sflag id/threshold 的同一个 slot。
  • overlay-fetch DMA descriptor{hbm-src, local/timem-dst, size, sflag};它的 sflag 是由 Target::GetOverlayReservedSyncFlagNumber()Target+0x534)构造的 immediate,通过 EncodeOverlaysForDmaEmitContinuationTailcall 发出。
每代宽度函数TPUSubtarget::getImmediateSizeInBits() @ vtable +0x340(reloc-walked R_X86_64_RELATIVE
宽度值BarnaCore = 16 (0x13c596a0); Viperfish / Ghostlite / 6acc60406 = 20 (0x13c5f5a0 / 0x13c61480 / 0x13c62fa0)
通用 packerBitCopy(dst, dst_bit, src, src_bit, nbits) @ 0x1fa0a900 — LSB-first;dst_bit == absolute bundle bit
TC imm encoderTensorCoreImmediatesEncoder::Encode — VXC 0x1eebee40, GLC 0x1f20d520, GFC 0x1f86de20
SCS imm encoderSparseCoreImmediatesEncoder::Encode — VFC 0x1ee75ee0, GLC 0x1eb563c0, GFC 0x1eb5bd20
TC imm 梯形表VXC 430/410/390/370/350/330(slot 0..5,stride −20,每个 w20);GLC = VXC+3 (433..333);GFC = VXC−7 (423..323)
SCS imm 梯形表67/47/27/7(所有 V5+);GLC 添加 215/195(wide 6-slot variant)
Slot allocatorResourceSolver::getFullImmediate @ 0x13be79a0(pool walk:+0xd8 records,+0x118 candidate list,+0x120 count)
Value choosergetPackedImm @ 0x13bec4e0call [vtable+0x340] ×4 = value-fit test)
Integer-imm familyencoding-id 0x2c = SyImm32 (getFirstSyImm32Encoding);0x1a = VyImm32 (getFirstVyImm32Encoding)
PF / JF imm6 × 16-bit — PF @ 256/272/288/304/320/338;JF proto +0x68..+0x7C(非 subtarget-virtual)
Branch target homeimmediate slot 0(signed 20-bit;EmitImmediate<…Immediates>(slot=0, …)
Overlay DMA sflagTarget::GetOverlayReservedSyncFlagNumber() = Target+0x534EncodeOverlaysForDma @ 0x14095f40

Immediate-Slot 宽度是 Subtarget Virtual

单个 immediate slot 的宽度不是烘焙进 encoder 的常量,而是通过 subtarget vtable 的 slot +0x340 读取;该 slot 会按 generation 解析到 TPUSubtarget::getImmediateSizeInBits()。四个具体 override 都是单指令函数,返回常量明确无歧义:

c
// TPUBcSubtarget::getImmediateSizeInBits   @ 0x13c596a0
return 16;   // BarnaCore (v4 path) — 16-bit immediate slot
// TPUVfcSubtarget::getImmediateSizeInBits  @ 0x13c5f5a0
return 20;   // Viperfish (v5e)
// TPUGlcSubtarget::getImmediateSizeInBits  @ 0x13c61480
return 20;   // Ghostlite (v6e)
// TPUGfcSubtarget::getImmediateSizeInBits  @ 0x13c62fa0
return 20;   // 6acc60406 (v7x / TPU7x)
```text

抽象基类 `TPUSubtarget` 的 `+0x340` slot 是 `__cxa_pure_virtual`;不存在 `TPUPfSubtarget` 或 `TPUJfSubtarget` class,因此 pre-V5 generations 完全不会通过这个 virtual 暴露它们的 immediate width(见 [Pre-V5 Generations](#pre-v5-generations-pufferfish-and-jellyfish))。

这个宽度正是 V5+ immediate encoders 发出的 `BitCopy` field width:`getImmediateSizeInBits` *就是*每代 immediate-slot 宽度,而 encoder 写入 `w20` cells 是因为 subtarget 声明为 20。有两个消费者读取它:

- `getPackedImm`(`0x13bec4e0`)通过 `call [TPUSubtarget vtable+0x340]`(四次,对应四个 integer-immediate encoding classes)并按返回宽度移位,测试候选值有多少高位非零;这是决定常量是否适合一个 slot 的 value-fit test。
- `getFullImmediate`(`0x13be79a0`)使用同一宽度,把过宽的值拆分为 16-bit low half 和 16-bit high half(proto immediate field 为 32-bit;slot 为 2016,因此 full-range value 占用两个 slots)。

> **注意 —** V5+ slot 是 20 bits,但 `getFullImmediate` 中的 lo/hi 拆分记录的是 source proto field 的 16-bit halves。重实现不能把 *slot width*20,即 bundle 中的容量)和 *split granularity*32-bit proto immediate 的 16-bit halves)混为一谈。单个 20-bit slot 仍然只携带一个 split value 的一半。

---

## TensorCore Immediate 梯形表(V5+64-byte bundle)

TensorCore bundle([Viperfish 64B](bundle-vf-64b.md))携带 **6 个 immediate slots**,由 `TensorCoreImmediatesEncoder::Encode` 写入。每代 encoder 都读取相同的六个 proto fields(`TensorCoreImmediates` message offsets `+0x18, +0x1c, +0x20, +0x24, +0x28, +0x2c` = words `a2[6..11]`,即 proto field = `+0x18 + 4*i`),并以 width 20 将每个 field `BitCopy` 到按 generation 固定的绝对 bit。Viperfish encoder 字面读取为:

```c
// asic_sw::deepsea::vxc::isa::TensorCoreImmediatesEncoder::Encode  @ 0x1eebee40
v17[0] = a2[6];  BitCopy(buf, 430, v17, 0, 20);   // imm slot 0
v17[0] = a2[7];  BitCopy(buf, 410, v17, 0, 20);   // imm slot 1
v17[0] = a2[8];  BitCopy(buf, 390, v17, 0, 20);   // imm slot 2
v17[0] = a2[9];  BitCopy(buf, 370, v17, 0, 20);   // imm slot 3
v17[0] = a2[10]; BitCopy(buf, 350, v17, 0, 20);   // imm slot 4
v17[0] = a2[11]; BitCopy(buf, 330, v17, 0, 20);   // imm slot 5

梯形表是统一的 −20 bits stride,slot 0 最高。Ghostlite(0x1f20d520)和 6acc60406(0x1f86de20)在结构上 field-identical——相同的六个 proto reads、相同的 width 20——但每代按常量偏移:

imm slotproto fieldViperfish (VXC) bitGhostlite (GLC) bit6acc60406 (GFC) bit宽度
0+0x1843043342320
1+0x1c41041340320
2+0x2039039338320
3+0x2437037336320
4+0x2835035334320
5+0x2c33033332320

每代 delta 是精确的:Ghostlite = Viperfish + 36acc60406 = Viperfish − 7,统一应用到每个 slot。该移位反映的是 immediate region 之上的 slots(512-bit word 顶部的 scalar/sequencer slots)布局在每代不同;immediate 梯形表本身保持 −20 的内部 stride。Slot 0 是 sequencer branch/call target 的 home——在 6acc60406 上它是 bit 423,与 Sequencer Slot 页中的 branch-target 观察匹配。

注意 — proto-field-to-slot 绑定是刚性的:immediate slot i 始终是 TensorCoreImmediates field +0x18 + 4*i,在所有三个 V5+ generations 中相同。每代唯一变化的是值被放置的绝对 bit。为某个 V5+ gen 构建的 decoder 只要应用 +3 / −7 偏移即可移植到其他 gen。


SparseCore Immediate 梯形表(V5+,32-byte bundle)

SparseCore scalar (SCS) bundle 为 32 bytes,在 Viperfish 和 6acc60406 上携带 4 个 immediate slots,由 SparseCoreImmediatesEncoder::Encode 写入(VFC 0x1ee75ee0;GFC variant 名为 SparseCoreScalarImmediatesEncoder0x1eb5bd20):

c
// asic_sw::deepsea::vxc::vfc::isa::SparseCoreImmediatesEncoder::Encode  @ 0x1ee75ee0
v13[0] = a2[6]; BitCopy(buf, 67, v13, 0, 20);   // imm slot 0
v13[0] = a2[7]; BitCopy(buf, 47, v13, 0, 20);   // imm slot 1
v13[0] = a2[8]; BitCopy(buf, 27, v13, 0, 20);   // imm slot 2
v13[0] = a2[9]; BitCopy(buf,  7, v13, 0, 20);   // imm slot 3
```text

Ghostlite 的 SCS encoder(`0x1eb563c0`)是一个 **6-slot wide variant**:同样的四个 base slots,再额外读取 proto fields `+0x28`/`+0x2c`(`a2[10]`/`a2[11]`)的两个 slots:

```c
// asic_sw::deepsea::gxc::glc::isa::SparseCoreImmediatesEncoder::Encode  @ 0x1eb563c0
...same 67/47/27/7 as above...
v17[0] = a2[10]; BitCopy(buf, 215, v17, 0, 20);  // imm slot 4 (GLC only)
v17[0] = a2[11]; BitCopy(buf, 195, v17, 0, 20);  // imm slot 5 (GLC only)
imm slotproto fieldVFC bitGLC bitGFC bit宽度
0+0x1867676720
1+0x1c47474720
2+0x2027272720
3+0x2477720
4+0x2821520
5+0x2c19520

base 4-slot 梯形表(67/47/27/7)在所有三个 V5+ gens 上逐字节相同——不同于 TensorCore 梯形表,SCS 梯形表没有每代 offset。只有 Ghostlite 添加 high pair(215/195),位于 32-byte word 的另一个更高区域,用于需要超过四个常量的 ops。


值如何被选择和放置 — ResourceSolver Walk

上面的 bit 梯形表说明每个 immediate slot 位于哪里;它们并不说明某个给定常量进入哪个 slot。这个决定是在每程序 slot pool 上进行的运行时分配,而不是静态的 per-encoding 表。两个函数负责它。

getPackedImm0x13bec4e0)对值分类。integer-immediate family 对 scalar immediates 使用 encoding-id 0x2cSyImm32),对 vector immediates 使用 0x1aVyImm32);chooser 写入 OpEnc class 5,并通过 getFirstSyImm32Encoding / getFirstVyImm32Encoding 选择。然后它通过 call [TPUSubtarget vtable+0x340](= getImmediateSizeInBits)运行 value-fit test,以获知一个 slot 容纳多少 bits。

ResourceSolver::getFullImmediate0x13be79a0)遍历 slot pool。ResourceSolverthis 携带 pool,而不是 subtarget:

c
// ResourceSolver::getFullImmediate  @ 0x13be79a0  (offsets relative to this == a1)
*(_DWORD *)out      = 5;                                   // OpEnc class 5 (integer-imm)
*(_BYTE *)(out + 5) = getFirstSyImm32Encoding(0, ...);     // encoding-id 0x2c (or 0x1a for VyImm32)
count   = *(uint *)(a1 + 0x120);    // +0x120: candidate-slot list count
list    = *(uint **)(a1 + 0x118);   // +0x118: candidate-slot id pairs (walked lo-half then hi-half)
records =  *(_QWORD *)(a1 + 0xd8);  // +0xd8 : ImmediateSlot[] records, 12 B each
                                    //         +0x0 allowed-value/constraint, +0x8 present flag
for (entry in list) {
    slot = list[entry];
    if (!_bittest64(&slotmask, slot)) continue;            // slot legal for this op?
    if (records[slot].present != 1)  continue;             // slot usable in this bundle?
    // match value.lo16 / value.hi16 against records[slot] allowed-value, record (half, ImmediateSlot)
    push_back(out_vec, pair(slot, ImmediateSlot{slot}));   // SmallVector<pair<uint,ImmediateSlot>,4>
}
```text

pool 在 `ResourceSolver` ctor(`0x13beb0a0`)中按程序构建,来源是 per-gen `MCBundleInfo`(`MCBundleInfoFactory::create` @ `0x13c799e0`,按 CPU string dispatch),其 slot-list-provider virtuals(`[+0x360]`/`[+0x368]`)填充 `+0x118` candidate list。`MaxImms`(`0x224e2b00`)/ `MinImmSlot`(`0x224e2bb8`)BSS globals 约束 slot range。因此,“immediate-slot resource table”就是 per-gen SparseCore SCS/TEC sequencer slot inventory 在 runtime pool 中的物化;每个 slot 携带的宽度是 `getImmediateSizeInBits`,它落入的 bit 是上面的 encoder 梯形表。

因此链路是:**operand-type → OpEnc class → integer-imm encoding-id `0x2c` → `ResourceSolver` 选择一个 free slot index → proto field `+0x18 + 4*idx` → `<gen>ImmediatesEncoder::Encode` 将其放到 per-gen bit。** 适合 slot 宽度的值占用一个 slot;更宽的值拆分成 low 和 high halves 跨两个 slots(上面的 `value.lo16` / `value.hi16` walk),两个 halves 从 pool 中取得两个不同的 candidate slots。

operand → OpEnc class 映射是 `ImmediateCompatibilityTable`(`0xaed36d0`,17 × 12 B,`{OperandType, compat_mask, OpEnc_class}`),由 `getOperandTypeRecord`(`0x13c63b80`,binary search)查找。`OperandType 4` → class `5`(integer-immediate chooser),compat `0x0f`(ZeroExt/OneExt/Shl/Imm32 全允许)。`canAddImmInternal`(`0x13bebce0`)读取 `MCInstrDesc` operand record `+0x23` 处的 operand-type byte,并在调用 `getPackedImm` / `getFullImmediate` 前送入这里。

---

## Sequencer Branch Target 位于 Immediate Slot 0

immediate slot 最重要的消费者是 sequencer。branch 或 call target ****存储在 sequencer slot 自己的 bytes 中——它是一个 signed 20-bit 值,放在 bundle 的 **immediate slot 0** 中;sequencer slot 中只有 opcode discriminator 决定该值是 PC-relative delta 还是 absolute bundle index(见 [Sequencer Slot](slot-sequencer.md))。V5+ SCS branch/call emitters 通过相同 immediate path 写入它:

```c
// isa_emitter::EmitBranchOp<…BranchRelative>  @ 0x13a5d3e0  (abs/rel are field-identical)
target = MCInst.getOperand(0).Imm;
if ((uint64_t)(target + 0x80000) >= 0x100000) return RetCheckFail();  // signed-20-bit range
EmitImmediate<SparseCoreImmediates>(/*slot=*/0, target);              // → immediate slot 0

range check (value + 0x80000) < 0x100000 精确对应 −524288 .. +524287——一个 signed 20-bit field,即单个 V5+ immediate slot 的完整宽度(getImmediateSizeInBits = 20)。在 6acc60406 (GF) 上,slot 0 是 TC bit 423;在 Viperfish 上是 430。因为 branch target 适合一个 slot,所以它永远不会触发 lo/hi split。barrier/sync ops(EmitBarrierSync<…ScalarMisc>)复用同一个 immediate slot 0 来存放 sflag id/threshold,因此 decoder 必须读取 bundle 的 immediate region——而不是 sequencer slot bytes——才能恢复 branch offset。

易错点 — LLVM-MC code emitter 对 branch encoding 贡献 bits;BRrel/BRabs/CALLrel/CALLabs 的 MC InstBits record 全为零。真正的 20-bit offset 由 proto-bundle EmitImmediate path 写入 immediate slot 0。重实现如果在 MC-emitted scalar bytes 中寻找 offset,将一无所获。见 Sequencer Slot


Pre-V5 Generations:Pufferfish 和 Jellyfish {#pre-v5-generations-pufferfish-and-jellyfish}

pre-V5 generations 携带 6 个 immediate slots,每个 16 bits,但通过不同的 codec——没有 subtarget-virtual width function(getImmediateSizeInBits 在基类中是 pure-virtual,且不存在 TPUPfSubtarget/TPUJfSubtarget)。BarnaCore(TPUBcSubtarget)override 返回 16,与 pre-V5 16-bit slot 一致,但 BarnaCore/Pufferfish slot positions 不是由 subtarget-driven encoder 写下的。

  • Pufferfish(51-byte bundle,PF 51B 将 6 个 immediates 作为 shared operand pool 中的 SlotMap<ImmValue, 6> 打包到绝对 bits 256 / 272 / 288 / 304 / 320 / 338(每个 16 bits),在 proto-build time 由 SetImmOrDie / VisitImmediateSlots<0..5> 绑定,而不是由 getImmediateSizeInBits 驱动的 BitCopy 梯形表绑定。slot allocation 是一个覆盖单一 shared pool 的 SlotMap——Pufferfish 版的 ResourceSolver walk——且一个 bundle 在所有 present slots 合计中最多只能命名六个不同的 immediates。
  • Jellyfish(41-byte bundle,JF 41B 将六个 16-bit immediates 作为 Bundle proto fields +0x68 .. +0x7C 携带,由 ValidateImmediate0x1e86da20)验证 < 0x10000,并以 proto+0x10 slot mask 为 key。slot assignment 是 JellyfishEmitter::FindFreeSlot
genbundleimm slots宽度positions / protocodec参考
Jellyfish (v2)41 B616proto +0x68..+0x7CBundle proto + FindFreeSlotJF 41B
Pufferfish (v4)51 B616256/272/288/304/320/338shared SlotMap + SetImmOrDiePF 51B
BarnaCore (v4 BC)16 (getImmediateSizeInBits)BarnaCore*MinImm fields仅 subtarget widthpositions 未遍历
Viperfish (v5p)64 B TC / 32 B SCS6 / 420TC 430/410/390/370/350/330; SCS 67/47/27/7TensorCoreImmediatesEncoder / SparseCoreImmediatesEncoder
Ghostlite (v6e)64 B TC / 32 B SCS6 / 4(+2)20TC 433/413/393/373/353/333; SCS 67/47/27/7(+215/195)同上 (GLC)
6acc60406 (TPU7x)64 B TC / 32 B SCS6 / 420TC 423/403/383/363/343/323; SCS 67/47/27/7同上 (GFC)

注意 — BarnaCore bit positions 尚未恢复。 getImmediateSizeInBits 确认 BarnaCore immediate slot 宽度为 16 bits,但 bit positions 位于 BarnaCoreSequencerScalar*ScalarFloatMinImm0..3 / BarnaCoreChannelVectorAlu*VectorFloatMinImm0..5 accessors 中(另一种 GetConcatenatedValue codec,不是 BitCopy 梯形表),此处未固定。这是 per-gen 梯形表中唯一的缺口;V5+ 表(VF/GL/GF,w20)和 PF/JF 16-bit pool 是完整的。


EncodeOverlaysForDma 对 Immediate Slot 的使用

immediate-slot 机制越过 per-instruction operand pool,延伸到 overlay-fetch DMA path。当程序太大而无法放入 local memory 时,backend 将其划分为 overlay segments,并为每段发出一个 DMA descriptor,以便从 HBM streaming。EncodeOverlaysForDma0x14095f40,作为 XLA_EncodeOverlaysForDma fiber task dispatch)是 per-overlay parallel encoder:它迭代 overlay array(BuildContext+0x98,count +0xa0),对每个 overlay 将工作扇出到 thread::Bundle(或低于阈值时 inline 运行),然后 JoinAll

per-overlay lambda(0x14096060)读取 IsaProgramIsaProgramsCaseGetIsaProgramUtil),索引 overlay,读取其 segment-start word(overlay+0xf8)和 set-value(overlay+0x100),加上 program base,并通过 IsaProgramUtil virtual 将结果 LloAddress 存入 OverlayMetadata_Overlay proto([util+0x28] setter;lambda 还调用 [util+0x178] proto getter 和 [util+0x160] FindOverlaySegment)。per-segment descriptor record 是 {overlay_number, overlay_begin, overlay_address / overlay_address_byte_offset, overlay_size, overlay_order}

该 descriptor 的 on-chip realisation 是 {hbm-src, local/timem-dst, size, sflag} DMA,而它的 sflag 是一个 immediate,由 overlay-reserved sync-flag number 构建。TensorCore continuation fetch 是 EmitContinuationTailcall0x12718ca0),其 overlay-fetch sequence 逐字节精确读取为:

c
// EmitContinuationTailcall  @ 0x12718ca0  (overlay-fetch segment, ~line 599)
sflag_no = Target::GetOverlayReservedSyncFlagNumber(target);          // = Target+0x534
sflag    = LloRegionBuilder::SflagImmPtr(rb, sflag_no, "overlay reserved sync flag", 26);
src      = LloRegionBuilder::CastAddr(rb, value, MemorySpace);        // overlay HBM source
size     = LloRegionBuilder::LloMemUnitFromGranules(rb, seg_size);    // segment size in granules
LloRegionBuilder::EnqueueDmaLocalInGranules(rb, src, dst, size, _, sflag, 0, 0, 0);
LloRegionBuilder::DmaDoneInGranules(rb, ..., sflag);                  // "continuation-tail-wait"
```text

因此 DMA descriptor 的 sflag operand 是一个 `SflagImmPtr` immediate——相同的 immediate-operand machinery,只是这里携带 reserved sync-flag id,而不是 branch target。next-segment source 和 size 来自保存在 Target-local SMEM 中的 program-descriptor words,全部为 `mov rax,[rdi+N]; ret` accessors:

| descriptor field | source (compile time) | on-chip realisation |
|---|---|---|
| hbm-src address | `OverlayMetadata_Overlay.overlay_address(_byte_offset)` | `Target::OverlayAddressWordOffset()` = `Target+0x810`; `CastAddr` |
| local/timem dst | overlay workspace | `Target::OverlayWorkspaceWordOffset/SizeWords()` = `Target+0x738`/`+0x740` |
| size | `OverlayMetadata_Overlay.overlay_size` | `LloMemUnitFromGranules`(granule count) |
| **sflag (immediate)** | overlay-reserved sync flag | `Target::GetOverlayReservedSyncFlagNumber()` = `Target+0x534`; `SflagImmPtr` |
| segment-begin | `OverlayMetadata_Overlay.overlay_begin` | segment 的 first bundle index |
| order | `OverlayMetadata_Overlay.overlay_order` | “natural” pack/fetch order |

SparseCore tile-overlay path(`overlayer::OverlayProgram` @ `0x1395bba0`)手工构造一个 `scDMA_HBM_TO_TIMEM_SIMPLErrrii`(opcode `0xfd7`),其 sflag operand 是 tile-overlay sflag(`SCTarget+0x1e8`),并通过 `getFirstSyImm32Encoding` 包装为 **`SyImm32`(encoding-id `0x2c`)**——即 `ResourceSolver` 分配到 slot 中的同一个 integer-immediate family。这就是 immediate-slot codec 和 overlay DMA 之间的直接联系:overlay sflag 是一个 `SyImm32` immediate(见 [TPUMCImm / SyImm32](tpumcimm-syimm32.md))。

runtime loader 将每个 segment 读取为 `{byte_offset, block.word_count}` 对(`BcsProgram` program header),受 invariant `overlay_address_byte_offset + overlay_address_block.word_count * bytes_per_word <= read_start + dma_alignment` 约束。这就是上面的 descriptor 解析到的具体 HBM fetch payload。

---

## 交叉引用

- [Bundle Model](bundle-model-overview.md) — VLIW issue-word contract,以及 `(TpuVersion, TpuSequencerType)` codec-metadata table。
- [Viperfish 64B Bundle](bundle-vf-64b.md) — 承载 6 × 20-bit immediate 梯形表的 TensorCore bundle。
- [Pufferfish 51B Bundle](bundle-pf-51b.md) — 位于 `256/272/288/304/320/338` 的 6 × 16-bit immediate SlotMap。
- [Jellyfish 41B Bundle](bundle-jf-41b.md) — 6 × 16-bit immediate proto fields `+0x68..+0x7C`。
- [Sequencer Slot](slot-sequencer.md) — 落入 immediate slot 0signed 20-bit branch/call target。
- [TPUMCImm / SyImm32](tpumcimm-syimm32.md) — allocator 放入 slot 的 integer-immediate operand(`encoding-id 0x2c`)。