CBREG 环形缓冲区寄存器
本页中的每个 opcode 值、位移、字段宽度和 enum 值,都是从
libtpu-0.0.40-cp314wheel(build-id89edbbe81c5b328a958fe628a9f2207d;buildlibtpu_lts_20260413_b_RC00)里的libtpu.so按字节精确读取的。.textVA 等于文件偏移0xe63c000。除非标注为vfc(Viperfish) 或glc(Ghostlite),地址均来自 gfc (6acc60406) 实例;三代 SC 在不同地址携带相同 schema。其他版本会有所不同。
摘要
CBREG 是 SparseCore 的硬件管理环形缓冲区寄存器:一个逻辑寄存器,持有线性内存区域上的滑动窗口,并产生会自推进、到末端回绕的地址流。它是 DMA descriptor ring 在 SC 中的对应物,即让 embedding datapath 遍历 lookup-index 列表,或把 embedding row 流式送入 tile buffer,而无需对每个元素重新计算地址的机制。TensorCore 循环会在每次迭代发出一个 imul/add,而 CBREG 会从一个由硬件免费递增并回绕的寄存器发出确定性序列 base, base+s, base+2·s, …, base+(N-1)·s, base, …。
从物理上看,CBREG 是三个子寄存器:{base, offset, size},存放在三个独立的硬件 bank(SC_{SCS,TAC,TEC}_CBREGS_{BASE,OFFSET,SIZE})中,但通过单个 4-bit CBREG index 作为一个寄存器寻址,因此每个 sequencer bank 有 16 个 CBREG。base 是一个带窗口的指针(指向 SMEM 或 TILE_SPMEM,地址空间在写入 base 时固定);size 是 offset 回绕的模数;offset 是实时位置。一次访问读取/写入 base + (offset mod size);一次 PostUpdate 访问还会推进 offset = (offset + step) mod size。二进制中没有 modulo 指令;回绕是 OFFSET counter 硬件的属性,而 “overflow” 按设计就是回绕,从不是 trap。
本页记录三个可重新实现的表面:(1) CBREG triple 和 CbregMetadata 子寄存器选择器,即 Read/Write ops 携带的 {0=BASE, 1=SIZE, 2=OFFSET} enum;(2) scalar-ALU CBREG-op 位布局,即统一的 ScalarAlu1 slot encoding(opcode 在 bundle bit 154,三个 operand field 在 slot-relative bits 10/15/21),它在 SCS/TAC/TEC scalar lane 之间以及三代之间共享,并列出每个 opcode 值;(3) slot-reference binding,即 AddCbreg 如何推进 OFFSET,Stream gather/scatter 的 IndirectOffsetSource=CBREG 如何消费窗口,以及 TEC vector-store scatter-add 如何引用 CBREG。opcode 名单本身由 SCS Scalar Opcode Enumeration 页面负责(AddCbreg=0x33 位于该页);bundle 字节布局由 SCS Engine 负责。本页是那两个页面所指向的 CBREG 语义。
对于重新实现,契约如下:
- 寄存器模型。 一个 4-bit CBREG index 在每个 bank 中选择 16 个寄存器之一;每个寄存器是在三个 bank 中的
{base, offset, size}triple,在一个 op 内由 6-bitCbregMetadataimmediate {0,1,2} 选择。 - scalar-ALU op encoding。 opcode 是 bundle bit 154(
ScalarAlu1,slot-relative bit 26)处的 6-bit field;三个 operand slot 位于 slot-relative bits 10 (Dest, 5-bit)、15 (Meta/Y, 6-bit)、21 (X, 5-bit)。Read/Write/Add/Move/SLD/SST 都复用这三个 slot。 - opcode 值。
Read=0x36、Write=0x35、Add=0x33、SLD/SST CircularBuffer及其 PostUpdate 变体,以及Move=0x00-primary +0x1b-sub(仅 gfc)均从各 op 的Matches()predicate 读取,跨代不变。 - 回绕与绑定。
addr = base + (offset mod size);PostUpdate 在硬件中推进offset = (offset + step) mod size;AddCbreg是显式的 2-operand{cbreg, delta}OFFSET 推进;Stream/vector-store 路径通过 4-bit selector 绑定 CBREG,用于 indirect-offset windowing 和 scatter-add。
| 寄存器文件 | 每个 bank 16 个 CBREG(4-bit selector),bank 为 SC_{SCS,TAC,TEC}_CBREGS_* |
| 每寄存器状态 | 3 个硬件 bank 中的 {base, offset, size} triple |
| 子寄存器选择器 | CbregMetadata(6-bit field,3 个有效值:BASE=0, SIZE=1, OFFSET=2) |
| Scalar op slot | ScalarAlu1 lane;opcode @bundle bit 154 宽度 6(slot-rel 26) |
| Operand fields | Dest @slot-rel 10/5 · Meta-or-Y @15/6 · X @21/5(decode word +0x18) |
| Scalar opcodes | Read 0x36 · Write 0x35 · Add 0x33 · SLD 0x3f/0x3e · SST 0x3d/0x3c · Move 0x00+0x1b |
| Vector CBREG selector | TEC VectorStore/Load Cbreg field & 0xF(4-bit → 16);shift 跨代变化(vfc >>21,glc >>22,gfc >>23) |
| 地址空间 | SMEM base(wrcbreg.smem.base)或 TILE_SPMEM base(wrcbreg.tilespmem.base) |
| 回绕 | offset = (offset + step) mod size,HW-implicit;无 trap,按设计回绕 |
| 跨代存在性 | 仅 v5+:VF (vfc, Viperfish)、GL (glc, Ghostlite)、GF (gfc, 6acc60406);jxc/pxc 中没有 |
NOTE — 本页负责 CBREG 语义,而不是 opcode 名单或 bundle 布局。
AddCbreg=0x33及其同族 opcode 值在 Scalar Opcode Enum 中编目;32-byte SCS bundle、slot base 和 27-bit scalar-slot template 在 SCS Engine 中说明。CBREG-as-Stream-offset-window 和 scatter-add slot 位布局在 Stream Gather/Scatter 中说明。本页记录 CBREG 是什么、如何寻址、如何回绕,以及这些 ops 如何绑定它。
CBREG 寄存器 Triple
用途
CBREG 是一个逻辑环形缓冲区寄存器,由编译器分配、初始化,然后交给硬件驱动。它存在的目的,是让 SC 能够产生回绕的地址流,用于 embedding-id 列表、gathered-row tile 或 gradient-accumulation 区域,而无需对每个元素重新计算 scalar 地址。该寄存器不是内存位置;它是一个小型硬件状态对象,由 address-generation 逻辑和 scalar/vector ops 按 index 引用。
三个子寄存器
一个 CBREG 选择 16 个逻辑寄存器之一;每个逻辑寄存器持有三个子寄存器值,它们位于三个独立的硬件 bank 中,但通过单个 4-bit index 作为一个寄存器寻址:
| 子寄存器 | Bank | CbregMetadata | 含义 |
|---|---|---|---|
base | SC_{SCS,TAC,TEC}_CBREGS_BASE | 0 (BASE) | 窗口起始地址,在 SMEM 或 TILE_SPMEM 中(地址空间在写入时固定) |
size | SC_{SCS,TAC,TEC}_CBREGS_SIZE | 1 (SIZE) | 窗口长度;用于回绕的模数 |
offset | SC_{SCS,TAC,TEC}_CBREGS_OFFSET | 2 (OFFSET) | 窗口内当前实时位置 |
寄存器类成员名在二进制中表现为 CBREG_BASE / CBREG_SIZE / CBREG_OFFSET;bank 后缀表现为 SC_<engine>_CBREGS_<sub>。base 是一个带窗口的指针:通过 wrcbreg.smem.base 写入时,它指向 SCS SMEM tier;通过 wrcbreg.tilespmem.base 写入时,它指向 per-tile TILE_SPMEM(见 Addressing)。size 和 offset 是该 buffer 内无量纲的 word/element 计数。
CbregMetadata 选择器
Read/Write CBREG ops 携带一个 immediate,用来命名该 op 触及三个子寄存器中的哪一个。该选择器占用 scalar instruction 中的 6-bit slot,但只有 {0,1,2} 有效,实际上只用了 2 位,较高 encoding 保留。validator 是 GetCbMetadata<…::CbregMetadata>(vfc 0x13998fe0,glc 0x13a046c0,gfc 0x13a7a6a0);其函数体将 immediate 精确映射如下:
// GetCbMetadata<vfc::CbregMetadata>(out, MCOperand operand) // 0x13998fe0
// operand must be an immediate (else LogFatal "operand.isImm()")
if (operand.imm == 2) metadata = 2; // OFFSET
else if (operand.imm == 1) metadata = 1; // SIZE
else if (operand.imm != 0) // any other value:
return MakeErrorImpl(
"CB Register Metadata operand must be an immediate with a value of "
"0 (Base), 1 (Size) or 2 (Offset). Provided value: " + imm);
else metadata = 0; // BASE (the imm == 0 fall-through)
```text
proto enum(`CbregMetadata`)一致:`CBREG_METADATA_BASE=0`、`CBREG_METADATA_SIZE=1`、`CBREG_METADATA_OFFSET=2`,随后是 `CBREG_METADATA_RESERVED_0..6`(七个保留 encoding)。runtime decode 侧携带匹配的诊断:`"invalid cbreg metadata: %d"` 和 `"Field cbreg_metadata of SparseCoreScalarAlu CbregMetadata is an enum and value 0x%x does not match any encodings."`
> **QUIRK — `AddCbreg` 不携带 metadata field;它总是以 OFFSET 为目标。** `Add` 是 offset-advance primitive,其 operand 集合是 `{which CBREG, delta}`,没有 `CbregMetadata` selector,因此它隐式写入 OFFSET 子寄存器。只有 `Read`/`Write` 需要显式 metadata immediate 来触及 `base`/`size`/`offset`。如果重新实现者把 `AddCbreg` 当作通用的 “add to a CBREG sub-register”,就会寻找一个 encoding 中并不存在的 metadata operand。
---
## Scalar-ALU CBREG Op Encoding
### 用途
scalar 路径会修改和读取 CBREG(设置其 base/size、清零 offset、推进它、复制它),并执行 scalar circular-buffer loads/stores。所有这些都是 `SparseCoreScalarAlu1` lane-1 ops;它们在三个 sequencer bank(SCS、TAC、TEC)之间以及三代之间共享一个统一的 slot layout。这是重新实现者发出 CBREG 指令时必须复现的 encoding。
### 统一 Slot Layout
scalar slot 的 decoded word 是 `+0x18` 处的 struct DWORD(DWORD index 6);opcode 是 slot-relative bit 26 处的 6-bit field,也就是 bundle-absolute bit 154(来自 [SCS Engine](scs-engine.md) 的 `ScalarAlu1` opcode 位置)。三个 operand fields 被每个 CBREG op 复用;每个 op 的含义不同,但位位置不变。下面的 bit shift 取自各 op 的 `…Field::GetConcatenatedValue()` accessor(vfc TAC instances `0x1e8e53c0..0x1e8e54a0`;gfc SCS `0x1eb7cac0..0x1eb7cbe0`):
| Field | Slot-rel bits | Width | Bundle-abs bit | Decode(来自 accessor) |
|---|---|---:|---:|---|
| `Dest` | `[10:14]` | 5 | 138 | `(word_0x18 >> 10) & 0x1F` |
| `field@15` | `[15:20]` | 6 | 143 | `(word_0x18 >> 15) & 0x3F`(CbregMetadata,或 ScalarY) |
| `field@21` | `[21:25]` | 5 | 149 | `(word_0x18 >> 21) & 0x1F`(X / CBREG selector) |
| `opcode` | `[26:31]` | 6 | 154 | masked `& 0xFC000000`,value `>> 26` |
### 每个 Op 的 Operand 映射
每个 CBREG op 以不同方式分配三个 operand slot。Operand `X@21/5` 和 `Dest@10/5` 在物理上是 5-bit,但 CBREG file 为 16,因此 CBREG 选择只使用低 4 位(绑定的 4-bit 约束来自 vector 路径的 selector,见 [Per-Bank CBREG Count](#per-bank-cbreg-count))。
```text
ReadCbreg (0x36): SREG[Dest] <- CBREG[X][metadata]
Dest @10/5 destination SREG Meta @15/6 sub-register {0,1,2} X @21/5 which CBREG
WriteCbreg (0x35): CBREG[Dest][metadata] <- ScalarY
Dest @10/5 which CBREG Meta @15/6 sub-register Y @21/5 ScalarY source
AddCbreg (0x33): CBREG[Dest].offset += ScalarY (mod size)
Dest @10/5 which CBREG Y @15/6 delta (ScalarY) (no metadata — implicit OFFSET)
MoveCbreg (0x00 primary + 0x1b sub @21): CBREG[Dest] <- CBREG[src] (gfc only)
Dest @10/5 destination CBREG src @15/6 source CBREG (copies whole {base,offset,size})
SLD CircularBuffer (0x3f) / PostUpdate (0x3e): SREG[Dest] <- CB[CBREG][offset]
SST CircularBuffer (0x3d) / PostUpdate (0x3c): CB[CBREG][offset] <- ScalarY
Dest @10/5 CB-sel @15/6 index @21/5
PostUpdate: after the access, offset = (offset + step) mod sizeOpcode 值
每个 op 的 Matches() predicate 从 ScalarAlu1 slot word 中 mask 出 6-bit opcode,并与一个 signature 比较;该 signature 就是 opcode。数值跨代不变,gfc 与 vfc/glc predicate 按字节相同。已确认值如下:
| Opcode | Mnemonic | Matches() 证据(gfc) |
|---|---|---|
0x36 | ReadCbreg | (word6 & 0xFC000000) == 0xD8000000;0xD8000000>>26 = 0x36(gfc 0x1eb7b560) |
0x35 | WriteCbreg | (word6 & 0xFC000000) == 0xD4000000;0xD4000000>>26 = 0x35 |
0x33 | AddCbreg | (word6 & 0xFC000000) == 0xCC000000;0xCC000000>>26 = 0x33 |
0x3f / 0x3e | ScalarLoadCircularBuffer / …PostUpdate | opcode field;PostUpdate 仅 VF/GL |
0x3d / 0x3c | ScalarStoreCircularBuffer / …PostUpdate | opcode field;PostUpdate 仅 VF/GL |
0x00+0x1b | MoveCbreg | (word6 & 0xFFE00000) == 0x3600000;>>26 = 0x00 primary,>>21 = 0x1b sub;仅 gfc |
QUIRK —
MoveCbreg是两级(escape)opcode,不是扁平的 6-bit 值。 它的Matches()mask 一个 11-bit field(& 0xFFE00000,bits 21–31),并比较== 0x3600000。primary 6-bit opcode 部分(>>26)是0x00,5-bit X field(>>21)携带 sub-opcode0x1b(27)。如果重新实现者只读取 6-bit primary,会把Move看作 opcode0x00,并与 control class 冲突;用于区分的位是 X-field sub-opcode。Move仅存在于 gfc(6acc60406);VF/GL 没有 scalarMoveCbreg。
一个 slot encoding-mode tag 将普通 Read/Write/Add/LD/ST 形式与 PostUpdate 形式区分开来;mode byte 携带 auto-increment bit,告诉硬件在访问后推进 OFFSET。PostUpdate-vs-plain 的判别器是独立的 …PostUpdate opcode predicate;这里不对精确的 mode-byte 值做 bit decode。
函数映射
| Function | Address | 角色 |
|---|---|---|
GetCbMetadata<vfc::CbregMetadata> | 0x13998fe0 | validate metadata immediate {0,1,2};否则 LogFatal |
GetCbMetadata<glc::CbregMetadata> / <gfc::…> | 0x13a046c0 / 0x13a7a6a0 | 相同逻辑,按 gen |
EmitReadCbregOp<vfc::CbregMetadata, …ReadCbreg> | 0x139983c0 | lower ReadCbreg MCInst → scalar slot |
EmitWriteCbregOp<…, ScsBundle, …WriteCbreg> (vfc) | 0x139e6420 | write CBREG,SCS bundle |
EmitWriteCbregOp<…, TacBundle / TecBundle, …> (vfc) | 0x13998b60 / 0x139d0d00 | write CBREG,TAC / TEC bundle |
EmitMoveCbregOp<…, ScsBundle / TecBundle, …MoveCbreg> (gfc) | 0x13ac9540 / 0x13a73c80 | copy CBREG triple;仅 gfc,无 TAC |
…TacScalarAlu1ReadCbregDestField::GetConcatenatedValue | 0x1e8e5400 | Dest >>10 & 0x1F |
…TacScalarAlu1ReadCbregCbregMetadataField::… | 0x1e8e53c0 | Meta >>15 & 0x3F |
…TacScalarAlu1ReadCbregXField::… | 0x1e8e53e0 | X >>21 & 0x1F |
…ScalarAlu1AddCbregOpcode::Matches (gfc) | 0x1eb7b5a0 | (word6 & 0xFC000000)==0xCC000000 → 0x33 |
…ScalarAlu1MoveCbregOpcode::Matches (gfc) | 0x1eb7b5c0 | (word6 & 0xFFE00000)==0x3600000 → 0x00+0x1b |
BitCopy | 0x1fa0a900 | LE bit-field packer (dst, dst_off, src, src_off, nbits) |
寻址与回绕 {#addressing-and-wraparound}
用途
CBREG 将它的 {base, offset, size} triple 转换为 effective address,并且对 PostUpdate ops 转换为自推进地址流。这是重新实现者分配 circular buffer 时编码的模型,也是硬件每次访问时执行的模型。
Effective-Address 与 Advance 公式
// Per-access effective address (conceptual; the wrap is HW-implicit):
addr = base + (offset mod size); // read or write this element
// PostUpdate access (mode tag 0x60) advances after the access:
offset = (offset + step) mod size; // wrap at the SIZE sub-register
```text
`SIZE` 是模数。普通(非 PostUpdate)访问保持 OFFSET 不变;只有 PostUpdate 形式(`scSLDCBREG…PostUpdate`、`scSST…PostUpdate`、TEC vector-store `…PostUpdateAdd*`,以及 Stream `post_update_indirect_offset_circular_buffer`)会推进并回绕它。显式 advance op `AddCbreg` / `llvm.tpu.cbreg.add.offset` 是 2-operand functional op `{cbreg, delta} → new_offset`;`.in.place` 变体就地修改 CBREG。
因此,初始化为 `{base, offset=0, size=N, step=s}` 的 CBREG 会发出确定性的 ring:
```text
base, base+s, base+2·s, …, base+(N-1)·s, base, base+s, …这是 address-generation 逻辑在无需逐元素 scalar 地址计算的情况下流式处理 embedding rows 或 lookup indices 所需的地址序列预测,即 SC 的硬件管理 DMA-descriptor-ring 对应物。
QUIRK — 没有 modulo 指令;回绕是 OFFSET counter,overflow 从不 trap。 二进制中不存在显式 modulo opcode。OFFSET 子寄存器就是 modulo-SIZE counter;编译器可见的 advance ops 只携带
{cbreg, delta},从不携带显式% size。因此回绕公式offset = (offset + step) mod size是从 op 形状加上 “circular buffer” 语义推断出来的;显式 modulo 是硬件内在行为,而不是被转录出来的指令。“Overflow” 对 CBREG 来说按设计就是回绕;不同于 SREG file(会 overflow 到 LSRA spill),CBREG 从不 trap,而是回绕。
双地址空间:SMEM vs TILE_SPMEM
base 子寄存器有两个 typed accessor,用于固定窗口指向哪个 memory tier。选择在写入 base 时完成;硬件上只有一个 CBREG 寄存器,但地址空间由哪个 wrcbreg.*.base intrinsic 设置它来确定:
llvm.tpu.rdcbreg.smem.base / .wrcbreg.smem.base -> SCS SMEM tier
llvm.tpu.rdcbreg.tilespmem.base / .wrcbreg.tilespmem.base -> per-tile TILE_SPMEM tier
```text
scalar `ScalarLoadCircularBuffer`(`scSLDCBREG`)对 SCS SMEM tier 开窗;TEC vector `TileSpmemLoadCircularBuffer` 对 TILE_SPMEM 开窗。`smem.base` 和 `tilespmem.base` accessor string 都存在于二进制中。这解答了 SCS scalar-memory 工作提出的 SMEM-address-space 问题:CBREG 是一个寄存器,持有指向 SMEM 或 TILE_SPMEM 的*带窗口指针*,在写入 base 时选择。
---
## 每个 Bank 的 CBREG 数量 {#per-bank-cbreg-count}
CBREG file 是**每个 sequencer bank 16 项**。绑定证据是 TEC vector load/store `Cbreg` field 上的 4-bit selector,并已跨 glc 和 gfc 确认:
| Bank | Count | Selector width |
|---|---:|---|
| `SC_SCS_CBREGS_*` | 16 | 4-bit |
| `SC_TAC_CBREGS_*` | 16 | 4-bit |
| `SC_TEC_CBREGS_*` | 16 | 4-bit |
> **NOTE — scalar field 是 5-bit,但 CBREG file 是 16,由 vector 路径的 4-bit selector 确定。** scalar-ALU `Dest@10` 和 `X@21` field 在物理上是 5-bit(足以表示 32),但 TEC vector Cbreg field 是硬性的 `& 0xF`(16 项)。scalar 5-bit field 的高位未用于 CBREG 选择。重新实现者必须将 CBREG file 定为 16;5-bit scalar slot 不是 32 个寄存器的证据。TAC 在 VF/GL 上有 CBREG(`EmitWriteCbregOp` 在 vfc/glc 下为 Tac 实例化),但 gfc 上没有。
---
## Slot-Reference Binding:其他 Slot 如何命名 CBREG
### 用途
CBREG 会从三个位置按 index 被引用:上面的 scalar-ALU ops、Stream-engine indirect-offset source,以及 TEC vector-store scatter-add。后两者使 CBREG 成为 embedding-table window。本节是绑定表面;那两个 slot 的位布局位于各自页面。
### Stream Indirect-Offset Source
[Stream gather/scatter](stream-gather-scatter.md) engine 通过 proto enum `IndirectOffsetSource` 选择其每元素 offset/size 来自哪里:
```text
IndirectOffsetSource (1-bit): SREG = 0 CBREG = 1选择 CBREG 时,index/offset 列表会通过 CBREG window 读取,且 post_update_indirect_offset_circular_buffer 按每个元素推进 CBREG offset(mod size);CBREG 就是 lookup-index buffer 上的 sliding window。Stream slot 自身没有 CBREG-index field;windowing CBREG 是 SCS 在发出 stream 之前设置好的那个(indirect-offset 路径绑定到 engine 的 CBREG state,而不是每个 stream 重新选择)。
TEC Vector-Store Scatter-Add
embedding-gradient scatter-add 将累积的 gradient 写入 CBREG-windowed TILE_SPMEM 区域。TEC vector-store family TileSpmemStoreCircularBuffer[PostUpdate]Add{Bf16,F32,S16,S32} 携带显式 4-bit Cbreg field,用来命名 16 个 CBREG 中哪个为目标 tile 开窗:
// TileSpmemStoreCircularBufferAdd{Bf16,F32,S16,S32} CbregField, decode word12 (+0x30):
Cbreg = (word12 >> shift) & 0xF; // which CBREG (16); & 0xF is gen-invariant
// shift gen-variant: vfc >>21 (0x1e9c1d00), glc >>22 (0x1eb4f160), gfc >>23 (0x1ecca4c0)
```text
完整的 store-slot field 集合(`{Mask, Stride, Offset, BaseAddress, Cbreg, Source}`)和 gradient-flow 细节在 [Stream Gather/Scatter](stream-gather-scatter.md) 与 [VectorStore Slot](vectorstore-slot.md) 中说明。与此处相关的绑定点是:vector store 通过 4-bit selector *命名* 一个 CBREG,post-update 其 offset,从而使 gradient tile 一次一个元素地流过 buffer。
### Embedding-Lookup 流程(引用在此组合)
```text
1. SCS allocates a CBREG and writes its triple:
wrcbreg.smem.base / wrcbreg.tilespmem.base <- index-list / tile base
wrcbreg.size <- per-window word count
wrcbreg.offset <- 0
2. Stream gather runs with IndirectOffsetSource = CBREG:
reads next index through the CBREG window,
computes HBM[table_base + index*row_stride], DMAs the row -> TILE_SPMEM,
post-updates the CBREG offset (mod size) so the next gather reads the next index.
3. TEC vector-loads the gathered rows (TileSpmemLoadCircularBuffer[PostUpdate]),
reduces, and on the backward pass
TileSpmemStoreCircularBufferPostUpdateAddF32 scatter-adds the gradient back
into the CBREG-windowed region, advancing the offset per store.compiler driver LinearStreamStartOpLowering::rewriteSparseCoreStreamOpToLLVM(以及 …AddStartOpLowering scatter-add sibling)接收一个 WideOffset 变体,它会解析为 SREG 值或 CBREG-sourced offset;这就是 stream 变成 CBREG-windowed 的解析点。
LLVM / MLIR Intrinsic 表面
面向编译器、用于驱动 CBREG 的 ops。下面所有名称都作为字符串存在于二进制中;read/write intrinsics 携带按子寄存器和按地址空间区分的变体。
| Op-name string | 角色 |
|---|---|
llvm.tpu.allocate.cbreg | 分配一个 CBREG(每 bank 16 个) |
llvm.tpu.cbreg.add.offset | offset += delta → new offset,wrap mod size |
llvm.tpu.cbreg.add.offset.in.place | 相同,但修改 CBREG |
llvm.tpu.copy.cbreg | 复制整个 CBREG triple → MoveCbreg |
llvm.tpu.rdcbreg.offset / .size | 读取 OFFSET / SIZE 子寄存器 |
llvm.tpu.rdcbreg.smem.base / .tilespmem.base | 读取 BASE(按地址空间) |
llvm.tpu.wrcbreg.offset / .size | 写入 OFFSET / SIZE |
llvm.tpu.wrcbreg.smem.base / .tilespmem.base | 写入 BASE(按地址空间) |
sc_tpu.advance_cb_offset / read_cb_offset | 用于 advance / read 的文本 MLIR op 名称 |
MLIR sc_tpu op creators 支撑这些(tpu_allocate_cbreg::create 0x146d6d80,tpu_cbreg_add_offset::create 0x146d7e60 带 OneResult/NOperands<2>,tpu_cbreg_add_offset_in_place::create 0x146d7f60,tpu_rdcbreg_offset 0x14734820,tpu_wrcbreg_offset/_size 0x14a30fe0/0x14a310e0)。SC ISel 通过 matchReadCbreg<13419u,13417u,13418u>(0x13b39200)和 <13420u,…>(0x13b39620)匹配 reads,即 rdcbreg.{offset,size,base} family 的 intrinsic IDs 0x3469..0x346c。
配置 Knobs
| Knob / string | 含义 |
|---|---|
circular_buffer_size(default 1000) | XLA emitter window-size estimate,不是 HW capacity |
min_circular_buffer_byte_count | 要分配的最小 CB buffer;"Invalid min_circular_buffer_byte_count value" validator |
" row size exceeds circular buffer capacity within SparseMapRow Emitter" | lookup row 超过 CBREG SIZE 时的 emitter error |
HardwareManagedCircularBufferMinSizeBytes(0x10e4a660) | legacy BarnaCore HW-managed CB minimum,与 v5+ SC CBREG 不同 |
is_circular_buffer flag | 触发 SC tile allocator 的 VFC HW-bug guard(不能将 CB 放入最后一个 TILE_SPMEM entry) |
NOTE —
circular_buffer_size=1000是 emitter estimate,不是 SIZE 子寄存器宽度。 XLA emitter 用于确定 buffer 大小的默认窗口大小是软件 knob;物理 CBREG SIZE 子寄存器 bit-width 属于 chip_parts geometry,不在 C++ 中。不要把 1000-word emitter default 与硬件容量混淆。HardwareManagedCircularBufferMinSizeBytes属于 legacy BarnaCore circular buffer,是不同于这里记录的 v5+ SC CBREG 的另一种机制。
跨代存在性
CBREG 是 v5+ SparseCore 特性。jxc (Jellyfish) 或 pxc (Pufferfish) namespace 下没有 Cbreg ops,这些代没有 SparseCore CBREG。在三代 SC 中,差异集中在 scalar PostUpdate(gfc 中移除,迁移到 TEC vector path)和 scalar MoveCbreg(gfc 新增)。
| Mechanism | VF (vfc, Viperfish) | GL (glc, Ghostlite) | GF (gfc, 6acc60406) |
|---|---|---|---|
| CBREG file(每 SCS/TAC/TEC bank 16 个) | yes | yes | yes(无 TAC) |
ReadCbreg / WriteCbreg / AddCbreg(scalar) | yes(0x36/0x35/0x33) | yes | yes |
MoveCbreg(scalar) | — | — | yes(0x00+0x1b) |
ScalarLoad/StoreCircularBuffer | yes(0x3f/0x3d) | yes | yes |
ScalarLoad/StoreCircularBufferPostUpdate | yes(0x3e/0x3c) | yes | —(moved to TEC vector) |
TEC TileSpmemLoad/StoreCircularBuffer | yes | yes | yes |
TEC …StoreCircularBufferPostUpdateAdd{dt} | yes(int/float) | yes(4 dtypes) | yes(4 dtypes) |
Stream IndirectOffsetSource = CBREG | yes | yes | yes |
smem.base + tilespmem.base CBREG variants | yes | yes | yes |
gen split 由 namespace presence 按字节确认:MoveCbreg 文件仅存在于 gxc/gfc 下(20 个实例,仅为 Scs 和 Tec bundles 提供 EmitMoveCbregOp,例如 0x13ac9540 / 0x13a73c80);EmitWriteCbregOp 在 vfc/glc 下为 Scs/Tac/Tec 实例化,但在 gfc 下仅为 Scs/Tec 实例化(gfc 下无 TAC)。jxc/pxc 下有零个 Cbreg 文件。
限制与未决项
| 项目 | 备注 |
|---|---|
CbregMetadata enum {BASE=0, SIZE=1, OFFSET=2} | proto + validator 一致,body 已读 |
Scalar-ALU CBREG slot layout(opcode @154/6,fields @138/5、@143/6、@149/5) | accessor shifts 已读;bundle-abs 来自 SCS slot base |
Opcode values Read 0x36 / Write 0x35 / Add 0x33 / Move 0x00+0x1b | Matches() immediates 已读,gen-invariant |
| 每 bank 16 个 CBREG(4-bit selector) | TEC vector Cbreg & 0xF(shift gen-variant:vfc/glc/gfc >>21/>>22/>>23) |
| 双地址空间(SMEM base / TILE_SPMEM base) | 两个 accessor string 均存在;两个 wrcbreg.*.base variants |
IndirectOffsetSource SREG=0 / CBREG=1 + scatter-add Cbreg binding | enum + vector-store Cbreg field |
| 跨代存在性(仅 v5+;Move 仅 gfc;PostUpdate 非 gfc-scalar) | namespace file presence |
回绕算术 offset = (offset + step) mod size | 由 op 形状 + circular-buffer 语义推断;无显式 modulo op |
SLD/SST 0x3f/0x3e/0x3d/0x3c opcode values | opcode-field roster;PostUpdate-bit 未完全 bit-decoded |
| 物理 OFFSET/SIZE 子寄存器 bit widths | chip_parts geometry,不在 C++ 中 |
PostUpdate step source(element-size vs fixed-1 vs operand Stride) | vector form 有 4-bit Stride;scalar step source 未经 bit-confirmed |
| 写入 SIZE mid-loop 是否合法以及 in-flight PostUpdates 的 HW ordering | proto 允许 WriteCbreg[SIZE];ordering 未恢复 |
scIMPLICIT_CBREG operand role(可能是 SLD/SST 的 default CB0) | 未解码 |
相关组件
| Name | Relationship |
|---|---|
GetCbMetadata<…::CbregMetadata>(0x13998fe0) | 验证 metadata immediate {0,1,2};BASE/SIZE/OFFSET decode |
EmitReadCbregOp / EmitWriteCbregOp / EmitMoveCbregOp | per-bundle lowering MCInst → scalar CBREG slot |
…ScalarAlu1AddCbregOpcode::Matches(0x1eb7b5a0) | 从 slot 读回的 0x33 opcode signature |
TEC …StoreCircularBufferPostUpdateAdd{dt} CbregField | 将 scatter-add 绑定到 window 的 4-bit CBREG selector |
BitCopy(0x1fa0a900) | 每个 scalar/vector encoder 都通过它写入的 LE bit-field packer |
交叉引用
- SCS Scalar Opcode Enumeration —
ScalarAlu1opcode roster,其中编目了AddCbreg=0x33、ReadCbreg、WriteCbreg、MoveCbreg。 - SCS (Scalar) Engine — 32-byte bundle 和 27-bit
ScalarAlu1slot template,CBREG-op opcode field(@154)位于其中。 - Stream Gather/Scatter — 引用 CBREG 的
IndirectOffsetSource=CBREGindirect-offset window 和 TEC vector-store scatter-addCbregfield。 - SparseCore Architecture — embedding datapath end to end;CBREG windowing 在 gather/compute/scatter pipeline 中的位置。
- SparseCore Overview — engine classes、per-gen SC presence,以及 host-table → HBM → SC gather path。
- TEC Engine — 对 CBREG-windowed tile 发出
TileSpmemLoad/StoreCircularBuffer的 vector engine。 - TAC Engine — VF/GL access engine,它也携带 CBREG scalar slot(gfc/6acc60406 下没有 TAC CBREG emitter)。
- VectorStore Slot / VectorLoad Slot —
Cbregfield 所属的完整 TEC vector circular-buffer slot family。 - M-Register Predicate Word — 覆盖每个 scalar slot、位于 CBREG-op opcode field 上方的 predication header。
- Binary:
extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d) - Index entry: Part IX — SparseCore & BarnaCore / SparseCore ISA — 返回索引