Skip to content

nf_descriptor(27 字段 Node-Fabric DMA 描述符)

本页所有地址均适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d,构建 libtpu_lts_20260413_b_RC00)。该二进制带有完整 C++ 符号;.text VMA == 文件偏移,基址 0xe63c000。其他版本会有所不同。

摘要

nf_descriptor_trace_entry 是一个分阶段 Node-Fabric DMA 描述符的线上 trace:它是 deepsea fabric 为把一个 buffer 从某个 chip 上的源端点移动到另一个(或在 multicast 情况下多个)chip 上的目标端点而 staging 的记录。"Node-Fabric" (nf) 是位于路由调度之下的跨节点 DMA 层:route table 回答“对此目标 chip 使用哪个输出链路”,net_router schedule 回答“在 step k,对这个 src→dst 执行 DMA”,而 nf_descriptor 命名的是实际{src_offset, src_resource, src_node, src_chip}{dst_offset, dst_resource, dst_node, dst_chip} 传输、它的长度、multicast/segmented 标志,以及它触发的三个独立 SyncFlag completion。该描述符是 deepsea OCI SHAPE-B DmaDescriptor 的 jxc 对应物,也是 jxc::DmaDescriptor V1 记录的线上形式。

该记录是一个 proto2 消息 asic_sw::driver::deepsea::jxc::nf_descriptor_trace_entry,即 PerformanceTraceEntry oneof 的 case 3。它有 27 个字段,除字段 1(id,一个 TracePoint enum)和字段 4(descriptor_source,一个 descriptor_source_value enum)外,全部为 uint32。C++ 内存布局不是 proto 字段顺序:字段 1–3 和 5–27 从偏移 0x180x7c 连续布局,但字段 4(descriptor_source)被放在线外偏移 0x80,并带有非零内存默认值 1BARNA_CORE)。这两个事实在下文被固定了两次:一次来自序列化器的 offset/wire-tag 对,一次来自 ::Clear 的清零块。

本页逐字段记录 27 字段布局及权威 C++ 偏移;三个 SyncFlag-update 通道(Source = “buffer free”,Destination = “data arrived”,Ack = “completion”)及其共享的 23 位 SyncFlagTarget 打包;HIB host-DMA 通道(字段 26/27);GetDmaSize / GetDmaTransactionId 访问器;相关的 bcs_internal BarnaCore-sequencer band;以及 deepsea GetDmaId 位编码器,它证明跨代 DMA 配对键是相同的逻辑 (tag, resource/core, node, chip) 元组,只是在现代硅片上被扩宽。承载这些描述符的 ICR DMA bandICR Node-Fabric DMA;解析多跳链路路径的路由表见 Route-Table Generation

对于重新实现,契约如下:

  • 27 字段记录:每个 proto 编号、名称、类型、wire tag 和 C++ 内存偏移,包括位于 0x80、默认值为 BARNA_CORE 的线外 descriptor_source
  • 三个 SyncFlag 通道及其 23 位 target pack {sync_flag[0:10] | resource[10] | node[11] | chip[12:23]},包括显式的 Destination pack 以及生成相同布局的 Source/Ack OCI fold。
  • HIB 通道(字段 26/27),它门控描述符是否还会触发 host-interface flag/ack。
  • deepsea GetDmaId 38 位复合键 transaction_id[0:21] | core_id[21:24] | chip_id[24:38],它逐字段与 jxc 27 位键交叉对齐,证明跨代配对等价性以及 chip 字段从 11→14 的扩宽。
消息asic_sw::driver::deepsea::jxc::nf_descriptor_trace_entryPerformanceTraceEntry oneof case 3
字段数27(uint32 × 25,TracePoint enum × 1,descriptor_source_value enum × 1)
C++ body0x180x7c 连续;descriptor_source 位于线外 0x80(默认 1
hasbits0x10(4 字节)
序列化器_InternalSerialize @0x1cf0ed20Clear @0x1cf0eca0_table_ @0x21c55ba0
SyncFlag 通道Source @0xf6982e0 · Destination @0xf698340 · Ack @0xf6983a0(+ HIB 字段 26/27)
SyncFlagTarget pack23 位:sync_flag[0:10] | resource[10] | node[11] | chip[12:23]
Size / id 访问器GetDmaSize @0xf6982a0(length≪10)· GetDmaTransactionId @0xf698260
deepsea 配对键GetDmaId(int) @0xf699ca0 — 38 位 txid[0:21]|core[21:24]|chip[24:38](chip mask 0x3fff

1. 27 字段记录

目的

该描述符端到端描述一次跨节点 fabric 传输:两个端点(offset + resource + node + chip)、字节长度、两个布尔 shape 标志(multicast / segmented),以及三个独立的 SyncFlag-raise 通道。每个已 staging 的描述符会发出一个 trace event;描述符的逐引擎执行(command issue、data-end)由 ICR Node-Fabric DMA 上的 nf band(case 6)追踪。

布局

下面的 C++ 偏移由 _InternalSerialize @0x1cf0ed20 精确到字节:每个字段都表现为一次 *((_DWORD *)this + N) 读取,并与写入输出流的 proto wire tag 成对出现(单字节 tag 使用 *a2 = TAG,字段 ≥16 的双字节 tag 使用 *(_WORD *)a2 = TAG)。descriptor-pointer 索引 N 映射到字节偏移 4*N

proto#NameTypeC++ offWire tag
1id (TracePoint)enum0x180x08
2tensor_nodeuint320x1c0x10
3trace_iduint320x200x18
4descriptor_sourceenum0x800x20
5node_iduint320x240x28
6chip_iduint320x280x30
7program_counteruint320x2c0x38
8source_offsetuint320x300x40
9source_resourceuint320x340x48
10destination_offsetuint320x380x50
11destination_resourceuint320x3c0x58
12destination_node_iduint320x400x60
13destination_chip_iduint320x440x68
14lengthuint320x480x70
15destination_is_multicastuint320x4c0x78
16destination_is_segmenteduint320x500x80 01
17destination_updateuint320x540x88 01
18destination_update_sync_flaguint320x580x90 01
19destination_update_resourceuint320x5c0x98 01
20source_updateuint320x600xa0 01
21source_update_sync_flaguint320x640xa8 01
22source_update_resourceuint320x680xb0 01
23ack_updateuint320x6c0xb8 01
24ack_update_sync_flaguint320x700xc0 01
25ack_update_resourceuint320x740xc8 01
26hib_updateuint320x780xd0 01
27hib_ack_updateuint320x7c0xd8 01

特性 — C++ 布局不是 proto 字段顺序。字段 1–3 和 5–27 从 0x180x7c 紧密排列;字段 4(descriptor_source)被拆到 0x80。按声明顺序布局 struct,或假设 proto 字段顺序等于内存顺序的重新实现,会从 node_id 开始误读每个字段。序列化器把字段 4 作为 *((int *)this + 32)(即 0x80)读取,同时在字段 3(0x18)和字段 5(0x28)wire emission 之间发射 wire tag 0x20;proto wire 顺序是正确的,只有内存放置被重排。这是 protobuf 字段 arena packing 的决策(带非零默认值的 enum 与尾部块分组),不是表中的错误。

序列化器中的两次 _WORD 存储(例如字段 16 的 *(_WORD *)a2 = 384)是小端双字节 varint tag 0x80 0x010x88 0x01、……,也就是 tag-and-wire-type 字节超过 0x7f 的 proto 字段号 16–27。

默认值与清除

::Clear @0x1cf0eca0 从另一个方向确认了布局。它清零三个 32 字节(ymm)块和一个尾部区域,然后把一个字段设置为非零默认值:

c
function nf_descriptor_trace_entry::Clear(this):       // 0x1cf0eca0
    has = *(u32*)(this + 0x10)                          // hasbits
    if (has & 0xFF):      zero ymm [this + 0x18]        // fields 1,2,3 + below (0x18..0x37)
    if (has & 0xFF00):    zero ymm [this + 0x38]        // 0x38..0x57
    if (has & 0xFF0000):  zero ymm [this + 0x58]        // 0x58..0x77
    if (has & 0x7000000):                               // the trailing block + descriptor_source
        *(u64*)(this + 0x78) = 0                        // hib_update(0x78), hib_ack_update(0x7c)
        *(u32*)(this + 0x80) = 1                        // descriptor_source default = BARNA_CORE
    *(u32*)(this + 0x10) = 0                            // clear hasbits
```text

`*(u32*)(this + 0x80) = 1` 存储是第二个独立证据,说明 `descriptor_source` 位于 `0x80` 且默认值为 `1`(`BARNA_CORE`):序列化器从 `0x80` 读取它,`Clear` 也在那里重置它。

### 嵌套 enum

```text
enum TracePoint:               TENSORCORE = 0,  BARNACORE = 1,  HIB = 2
enum descriptor_source_value:  TENSOR_CORE = 0, BARNA_CORE = 1, HIB = 2, HIB_HBM_QUEUE = 3
enum Constants:                NUM_LOG_LINES = 2

descriptor_source 命名 staging 该描述符的引擎;内存默认值 1BARNA_CORE)由 Clear 安装。TracePoint id(字段 1)区分 band 内的 trace-event 子类型(TENSORCORE / BARNACORE / HIB)。


2. 三个 SyncFlag-Update 通道

目的

一个 Node-Fabric DMA 在完成时最多可以触发三个独立的 SyncFlag,每个端点角色一个。每个都是 deepsea-descriptor 对 completion semaphore 的类比:源端在不再需要源 buffer 时触发 "buffer free" flag,目标端在远端端点触发 "data arrived" flag,ack 通道触发 "completion" flag。每个通道都由一个 wrapper accessor 暴露,该 accessor 先以 EntryDataCase == 3cmpl $3, 0x30(rax),即 oneof tag)门控,再以自己的 *_update enable 字段门控,最后打包一个 23 位 SyncFlagTarget

23 位 SyncFlagTarget pack

三个通道都生成相同的 target 布局:

text
SyncFlagTarget (23 bits):
  bits  0..9  : sync_flag   (10 bits, mask 0x3ff)
  bit  10     : resource    (1 bit)
  bit  11     : node        (1 bit)
  bits 12..22 : chip        (11 bits, mask 0x7ff << 12 = 0x7ff000)
```text

最清晰的证据是 `DestinationSyncFlagTarget` @`0xf698340`,它显式打包字段(没有 SIMD fold)。`v2` 是 wrapper 偏移 `+0x28` 处的内部 `nf_descriptor` 消息指针(`*(v1+40)`);门控条件是 `EntryDataCase == 3` 且 `destination_update != 0`:

```c
function DestinationSyncFlagTarget(wrapper):           // 0xf698340
    msg = wrapper.entry                                 // *(wrapper + 0x10)
    if (*(u32*)(msg + 0x30) != 3) return 0              // EntryDataCase != nf_descriptor
    nf  = *(ptr*)(msg + 0x28)                           // inner nf_descriptor message
    if (nf[21] == 0) return 0                           // destination_update (0x54) disabled
    return  (nf[17] << 12) & 0x7FF000                   // destination_chip_id   (0x44) -> chip[12:23]
          | ((nf[16] & 1)  << 11)                       // destination_node_id   (0x40) -> node[11]
          | ((nf[23] & 1)  << 10)                       // destination_update_resource (0x5c) -> resource[10]
          | (nf[22] & 0x3ff)                            // destination_update_sync_flag (0x58) -> sync_flag[0:10]

五次读取 nf[16]/nf[17]/nf[21]/nf[22]/nf[23] 位于 C++ 偏移 0x40/0x44/0x54/0x58/0x5c,正是 §1 中的 destination_* 字段 12、13、17、18、19。这与表逐字节一致。

SourceSyncFlagTarget @0xf6982e0(门控 source_update@0x60)和 AckSyncFlagTarget @0xf6983a0(门控 ack_update@0x6c)通过共享的 OCI SyncFlag-target fold 达到同一个 23 位布局:用 vpunpcklqdq{node_id, *_update_sync_flag} 交错到一个向量中,用 lane multiplier [1, 0x400, 0x800, 0x1000](fold table @0xa2c2560)执行 vpmulld,再用 [0x3ff, 0x400, 0x800, 0x7ff000](mask @0xa2d5e00)执行 vpand,最后水平 OR。multiplier/mask 对把 lane 0 → sync_flag[0:10]、lane 1 → resource[10]、lane 2 → node[11]、lane 3 → chip[12:23],也就是 Destination 通道显式打包出的同一个 23 位 target。

注意 — Source/Ack fold 使用 {node_id, sync_flag} 作为输入向量,因此这两个通道中的 bit-10 "resource" 位是从 node_id 的低位派生的,而不是来自单独的 resource 字段(Source/Ack 通道把 node-as-resource 编码进去)。Destination 通道读取真实的 destination_update_resource 字段。这是通道之间的一个小语义不对称;位布局相同(HIGH 置信度 — multiplier/mask 已逐字节解码,但未构造 fold lane 1 等于 Destination 的 (resource & 1) << 10 的符号证明)。

HIB 通道

不存在第四个 SyncFlagTarget accessor。相反,字段 26/27(hib_update@0x78hib_ack_update@0x7c)形成 host-interface (HIB) 通道:这两个 bit 选择描述符是否还会触发 HIB 侧 flag 和/或 ack。它们由 jxc-only host-DMA 聚合器(DeriveHostDmaTransfersnf_descriptor_hib 路径)消费,并折叠进 host-DMA timeline。只构建设备侧 fabric 路径的重新实现可以把它们视为不透明 enable bit。

陷阱 — 第四个 wrapper accessor UpdatedSyncFlagTarget @0xf698400 与上面三个并列存在,但它不是 nf_descriptor 通道。它门控 EntryDataCase 0xbbrn_sync_wait)/ 0x9cs_external_sync_flag_update),属于 TC/BarnaCore sync band,不属于 Node-Fabric descriptor。nf_descriptor 正好携带三个 SyncFlag 通道外加 HIB 通道;不要把第四个 accessor 接入此路径。


3. Size 和 Transaction-Id 访问器

另外两个 wrapper accessor 会读取此记录,但不打包 SyncFlag target:

  • GetDmaSize() @0xf6982a0 — 对 case 3(nf_descriptor)返回 length(@0x48) << 10,即以 1 KiB 为单位的字节长度。对 case 0x13(BMEM nf arm)则返回 (@0x2c) << 10。重新实现必须左移 10 才能恢复字节数;描述符存储的是 KiB。

  • GetDmaTransactionId() @0xf698260 — 对 nf_descriptor case 返回 0(那里没有 transaction id);它只在 case 0x13(BMEM arm)中填充,并打包 {((@0x18 bit-0) << 11) | ((@0x28) & 0x700) | ((@0x20) & ~0xfff) | (@0x28 low byte)},即 BMEM transaction id。

陷阱 — length 以 KiB 为单位,不是字节。把 length 直接当作字节数读取的 DMA-timeline 重新实现会把每个传输都少报 1024 倍。<< 10 位于 GetDmaSize,不在描述符中。


4. bcs_internal BarnaCore-Sequencer Band

目的

bcs_internal_trace_entryPerformanceTraceEntry oneof 的 case 15)是 BarnaCore-sequencer 的内部可观测性 band,即 BarnaCore 对 TC cs_internal band 的对应物。它不是 DMA 描述符,但共享同一个 proto family 和同一个 data_field marker/operand sentinel 方案,并且是 BarnaCore 在其驱动的 descriptor staging 周围触发的 band(trace marker、step boundary、scalar fence、host interrupt、sync-trace start/stop)。这里包含它,是因为它的 data_field 携带 DMA band 使用的同一种跨代 marker 编码。

布局

7 字段布局由 _InternalSerialize @0x1cf152a0::Clear @0x1cf15260 精确到字节:

proto#NameTypeC++ offWire tag
1id (TracePoint)enum0x300x08
2tensor_nodeuint320x180x10
3data_fielduint320x1c0x18
4sync_flag_numberuint320x200x20
5program_counteruint320x240x28
6sync_sfence_enduint320x280x30
7sync_sfence_startuint320x2c0x38

hasbits @0x10_table_ @0x21c56e80。与 nf_descriptor 一样,字段 1(id)位于线外:序列化器把它读作 *((int *)this + 12)0x30),而字段 2–7 从 0x18 开始连续。::Clear 清零 0x18 处的一个 xmm 块(16 字节,0x180x27)以及 0x28 处的一个 qword,然后写入 *(u32*)(this + 0x30) = 122,确认 id 位于 0x30,且默认值 0x7a = 122

每个 id 的 XLine 映射

6 个 TracePoint id 通过 Component() @0xf697f40(case-15 arm → bcs sub-table @0xab885fc)映射到 BarnaCore device line;名称由 TpuComponentName @0x1c8ebb60 验证:

idTracePointTpuComponentXLine name
122BRN_TRACE_INSTRUCTION0x3b (59)"Barna Core Trace Instruction"
123BRN_SET_TRACEMARK0x3c (60)"Barna Core Step"
124BRN_SYNC_START_STOP_TRACE0x16 (22)"Barna Core Sync Flag"
125BRN_HOST_INTERRUPT0x3d (61)"Barna Core Host Interrupt"
126BRN_FENCE_START0x3e (62)"Barna Core Fence"
127BRN_FENCE_END0x3e (62)"Barna Core Fence"

Constants: NUM_LOG_LINES = 1

data_field marker/operand sentinel

bcs_internal 由 V1 路径 ConvertTraceMarksAndInstructionsToXPlane<jxc> @0xf260960 消费,不是由注册的 CoreDispatcher subscriber 消费(不存在 "bcs" subscriber)。data_fieldcs_internal band 携带的同一个跨代 marker,由三个共享 tracker 解释:

c
// step boundaries: id 123 (XLine 0x3c "Barna Core Step") via TraceMark() @0xf698140
//   StepTracker::ProcessTraceEntry @0xf2c4480, data_field at TraceMarkEntry+0x8:
data_field in {0x7ffffffc, 0x7ffffffd}            -> step-boundary sentinel
data_field & ~1 == 0x7ffffffe                     -> step START / END marker (begin/end)
data_field <= 1                                   -> dropped (no-op)
2 .. 0x7ffffff9                                   -> nested step-id push (the step name)

// per-instruction operand: id 122 (XLine 0x3b) via RunTracker::ProcessTraceOperand @0xf2c4460:
if (data_field >= 0xF0000000)  run_id = data_field & 0xfffffff   // run-boundary marker
else                            data_field is a per-instruction operand

// overlay open/close (TRACE_INSTRUCTION fan-out) via OverlayTracker::ProcessTraceOperand @0xf2c3e40:
operand kind 0x9  -> overlay close
operand kind 0xd  -> overlay open
```text

Scalar fence(id 126/127,XLine `0x3e`)使用 `ScalarFenceStart()` @`0xf698020`(门控 `sync_sfence_start`@`0x2c`)/ `ScalarFenceEnd()` @`0xf698080`(门控 `sync_sfence_end`@`0x28`);fence span 通过 `GetOrCreateLine(0x3e)` 落到 XLine `0x3e`。`BRN_SYNC_START_STOP_TRACE`(124,XLine `0x16`)使用 `SyncFlagValue()` @`0xf6984a0` 读取 `data_field`。id 124/125 的 begin/end-vs-point span 模型未能从 V1 builder 中隔离(LOW 置信度 — 可能是 point event,未逐字节确认)。

---

## 5. deepsea GetDmaId 位编码器

### 目的

DMA-timeline 构建通过一个合成的 **`dma_id`** 复合键,把 begin event 与其匹配的 end event 配对。jxc `Dma` subscriber 以 `FlatHashMap<dma_id>` 为键;deepsea / 现代代际通过 `GetDmaId` 使用同样的配对。证明两个键是相同的逻辑元组,并且现代代际正好按 trace header 的扩宽方式扩宽其组成部分,就闭合了 jxc↔deepsea DMA-timeline 等价性。

### 38 位 deepsea 键

`GetDmaId(int)` @`0xf699ca0` 是 `pxc::profiler::TraceEntry` 上的模板(该单元中唯一的实例化;通过通用 `profiler::TraceEntry` 表面由 vfc/vlc/glc/gfc 共享)。它分派 proto oneof 字段号(`0x96` 个 arm),选择一个 `TraceIdHeader`(int 参数选择最多三个 command header 之一,默认选择 global),并用一种位布局组成 38 位键。组合尾部 @`0xf69a444` 读取 `TraceIdHeader` 字段 `{transaction_id@0x18, core_id@0x1c, chip_id@0x20}`:

```c
// composition tail (0xf69a444); hdr is the selected TraceIdHeader
txid = *(u32*)(hdr + 0x18)                          // transaction_id
core = *(u32*)(hdr + 0x1c)                          // core_id
chip = *(u32*)(hdr + 0x20)                          // chip_id
dma_id =  (txid & 0xFF)                             //  -> transaction_id[0:8]
        | (txid & 0x1FFF00)                         //  -> transaction_id[8:21]
        | ((core & 7)   << 21)                      //  -> core_id[21:24]
        | ((u64)(chip & 0x3FFF) << 24)              //  -> chip_id[24:38]
// presence bit dl = 1

这在反编译中逐字节精确:单个表达式 v4 = (u32)v3 & 0x1FFF00 | ((v6[7] & 7) << 21) | ((u64)(v6[4] & 0x3FFF) << 24); return v4 | (u8)v3; 其中 v6 是 header 指针,v6[6](=+0x18)=transaction_id,v6[7](=+0x1c)=core_id,v6[4*2](=+0x20)=chip_id。

text
deepsea dma_id (38 bits):
  bits  0..20 : transaction_id   (21 bits — per-transfer tag)
  bits 21..23 : core_id          ( 3 bits — TC0/TC1/SC0..SC3 selector)
  bits 24..37 : chip_id          (14 bits, mask 0x3fff — the chip in the pod)
```text

6 个 `CmdDmaIdFromEntry<…>` helper @`0xf69a500`–`0xf69a6e0`(用于 `OciCommonReadCmdIssuedFromEngine` / `MemReadReqFromEngine` / `WriteCmdAcceptedAtMn` / `OciWriteCommand` / `OciReadCommand` / `CompletedInTcs`)在使用 int selector 从最多三个 trace_id_header 中选择一个之后,组成相同布局(OCI command 最多携带三个)。`GetDmaId` 只被调用一次,即由 `ConvertTpuTraceToXPlane<pxc>` @`0xf26c8d9` 以 selector `0`(第一个/cmd0 header)调用。

### 与 jxc 键的跨代对应关系

jxc `GetDmaId()` @`0xf698180`(27 位键)从 jxc nf 记录组成相同逻辑元组。对于 `nf_descriptor` arm(case 3),它读取 `{trace_id@0x20, node_id@0x24, chip_id@0x28, descriptor_source@0x80}`,并打包 `(u8)trace_id | (trace_id & 0x1F00) | ((descriptor_source & 3) << 13) | (node_id << 15) | ((chip_id << 16) & 0x7FF0000)`:

```text
jxc dma_id (27 bits):              deepsea correspondence:
  trace_id[0:13]              <->  transaction_id[0:21]    (per-transfer tag; widened 13 -> 21)
  descriptor_source[13:15]    <->  core_id[21:24]          (jxc 2-bit engine selector -> deepsea 3-bit core_id)
  node_id[15]                 <->  (folded into core_id)   (jxc 1-bit tensor-node selector)
  chip_id[16:27] (11b)        <->  chip_id[24:38] (14b)    (widened 11 -> 14)

(jxc descriptor-resource 角色由 descriptor_source 承载,即 staging 描述符的 BarnaCore/TensorCore/HIB 引擎,打包进 bits 13:15 的 2-bit slot;deepsea core_id 是类似的 3-bit core selector。)

特性 — deepsea / 现代代际把 dma_id chip 字段扩宽到 14 位(mask 0x3fff),这与 trace header 跨代经历的 chip_id 11/12→14 扩宽相同。每代 proto2 chip_id 字段都是 uint32;14-bit mask 是最大扩宽值,对 pxc(header 中 12-bit chip)来说分配过多,但恰好适配扩宽后的 vfc/vlc/glc/gfc 代际。因此 DMA-pairing key 跟踪的 pod-address 扩宽与 trace header 相同。这证明跨代配对键是同一个逻辑 (tag, resource/core, node, chip) 元组,只是按代际扩宽。

陷阱 — jxc GetDmaId simple arm @0xf69824e(VMEM-ICI / SMEM / IMEM / HIB engine 的 fall-through)进入时 eax = 0ecx = 0,返回 dma_id = 0 且 presence dl = 0,也就是没有有效 dma_id,会被 subscriber 的 presence test 丢弃。它不会返回 id & 0xff。只有 HBM、VMEM_HBM 和 BMEM arm 会生成丰富的复合键。

注意 — vfc/glc/gfc 没有逐代 GetDmaIdGetDmaId(int) 只是 pxc 模板;现代代际把 DMA band 折叠进 ICI/intra-DMA band(见 Intra-Chip DMA Descriptor)。跨代已证明是相同元组,但尚未定位到重新内联计算它的现代代际 DMA-end consumer(CONFIRMED-PARTIAL)。


6. 函数映射

FunctionAddressRole
nf_descriptor_trace_entry::_InternalSerialize0x1cf0ed2027 字段序列化器(offset/tag 证据)
nf_descriptor_trace_entry::Clear0x1cf0eca0清零 + descriptor_source=1 默认值
nf_descriptor_trace_entry::_table_0x21c55ba0parse table
…SourceSyncFlagTarget0xf6982e0"buffer free" flag(OCI fold)
…DestinationSyncFlagTarget0xf698340"data arrived" flag(显式 pack)
…AckSyncFlagTarget0xf6983a0"completion" flag(OCI fold)
…UpdatedSyncFlagTarget0xf698400非 nf — brn_sync_wait/cs_external band
…GetDmaSize0xf6982a0length << 10(KiB→bytes)
…GetDmaTransactionId0xf698260BMEM transaction id(nf 为 0)
OCI SyncFlag fold (mul / mask)0xa2c2560 / 0xa2d5e00[1,0x400,0x800,0x1000] / [0x3ff,0x400,0x800,0x7ff000]
bcs_internal_trace_entry::_InternalSerialize0x1cf152a07 字段序列化器
bcs_internal_trace_entry::Clear0x1cf15260清零 + id=122 默认值
Component0xf697f40band→XLine(bcs sub-table @0xab885fc
ConvertTraceMarksAndInstructionsToXPlane<jxc>0xf260960V1 bcs consumer
jxc GetDmaId0xf69818027 位键(jt @0xab88674
deepsea GetDmaId(int)0xf699ca038 位键(jt @0xab88c40
CmdDmaIdFromEntry<…> × 60xf69a5000xf69a6e0OCI command-header key helper
ConvertTpuTraceToXPlane<pxc>0xf26c8d9唯一的 GetDmaId(0) caller

7. 注意事项

  • 双字节 tag 的端序。 字段 ≥16 使用小端存储的双字节 varint wire tag(*(_WORD *)a2 = 384 即字节 0x80 0x01)。发射这些 tag 的重新实现必须先写低字节。
  • KiB 长度单位(§3)是 DMA-timeline 重建中最常见的 off-by-1024 错误来源。
  • descriptor_source 放置(§1)会打破天真的声明顺序 struct 布局;应先布局 0x180x7c,再把 descriptor_source 放到 0x80
  • Multicast/segmented 标志(字段 15/16)会改变目标端点的解释方式(一个 chip vs. fan-out 集合);SyncFlag 通道仍然每个描述符只触发一个 target。
  • pxc GetDmaId 是唯一显式 key consumer;现代代际 DMA timeline 把配对折叠进逐代 ICI/intra-DMA 路径(§5 NOTE),因此捕获的 vfc/glc/gfc trace 不会直接执行此函数。

交叉引用