Skip to content

Latest commit

 

History

History
426 lines (329 loc) · 22.2 KB

File metadata and controls

426 lines (329 loc) · 22.2 KB

iTXTech fdnext DecodePack 规范(JSON)

本仓库把“厂商料号解码”做成纯数据的 iTXTech fdnext DecodePack(JSON)。@itxtech/fdnext-core/decodepack 负责把 DecodePack JSON specs 编译成 @itxtech/fdnext-core 可消费的 decoder,默认入口是 defaultDecodePack + compileDecodePack(defaultDecodePack)

本文是语法/API 参考,按需要查阅相应章节。维护仓库 PN 规则时使用 PN 编写规范;测试范围统一见 验证指南

1. PartDecodeSpec

最基础的 PartDecodeSpec 是“匹配 + 直接赋值”。下面只演示厂商前缀判断;产品线、容量和完整 PN 不能由这个前缀直接赋值,需由后续结构化规则确定。

{
  "id": "vendor.micron.prefix.mt",
  "priority": 100,
  "normalize": ["trim", "uppercase", { "remove": [" ", ",", "&", ".", "|"] }],
  "match": { "kind": "prefix", "value": "MT" },
  "set": {
    "device": { "domain": "memory", "vendor": "micron" }
  }
}

字段说明:

  • id: spec 唯一标识,建议 vendor.<vendor>.<kind>.<name>
  • priority: 数字越大越优先(默认 0)。引擎会按优先级从高到低尝试解码器。
  • normalize: 对输入料号进行预处理(见下)。
  • match: 匹配条件(见下)。
  • set: 匹配成功后直接写入 native draft(无需 tokenDecoder 时使用)。
  • tokenDecoder: 结构化 token 解析(见下)。

normalize

normalize 的步骤按顺序执行:

  • "trim":去除首尾空白
  • "uppercase":转大写
  • { "remove": [...] }:移除指定字符(逐个替换为空)

match

match.kind 支持:

  • "prefix"value 为前缀字符串
  • "regex"value 为正则表达式字符串,可选 flags

2. Token 解码(tokenDecoder)

适用于“料号内部由固定位置/可选前缀/表驱动字段组成”的情况。通过 steps 把 rest(未消费的字符串)逐段解析到上下文变量,再用 assign 构造输出对象。

下面的局部表演示语法,不是厂商 ordering 证据;实际 mapping 按 PN 编写规范 和产品线资料准入。

{
  "id": "vendor.kioxia.token.tc.v1",
  "priority": 920,
  "normalize": ["trim", "uppercase", { "remove": [" ", ",", "&", ".", "|"] }],
  "match": { "kind": "prefix", "value": "TC" },
  "tokenDecoder": {
    "stripPrefixes": ["TC"],
    "tables": {
      "density": { "G3": 8192 },
      "basePackage": { "XB": "BGA", "XL": "LGA" },
      "detailPackage": { "BGA:1": "BGA-224, 14x18x1.46" }
    },
    "steps": [
      { "op": "take", "len": 2, "to": "densityCode" },
      { "op": "map", "from": "densityCode", "table": "density", "to": "density" },
      { "op": "take", "len": 2, "to": "packageCode" },
      { "op": "map", "from": "packageCode", "table": "basePackage", "to": "basePackage" },
      { "op": "take", "len": 1, "to": "detailCode" },
      { "op": "tpl", "template": "{{basePackage}}:{{detailCode}}", "to": "detailKey" },
      { "op": "map", "from": "detailKey", "table": "detailPackage", "to": "detailPackageValue", "default": "" },
      { "op": "fallback", "primary": "detailPackageValue", "secondary": "basePackage", "to": "package" }
    ],
    "assign": {
      "device.partNumber": { "$var": "partNumber" },
      "device.domain": "memory",
      "device.vendor": "kioxia",
      "device.chipKind": "raw_nand",
      "fields.density": { "$var": "density" },
      "fields.package": { "$var": "package" },
      "meta.ruleId": "vendor.kioxia.token.tc.v1",
      "meta.fieldProfile": "raw_nand",
      "meta.capabilities": ["part.decode", "part.search"]
    }
  }
}

tokenDecoder.stripPrefixes

在执行 steps 前,依次从 rest 开头剥离固定前缀(仅当 rest.startsWith(prefix) 时剥离)。

DecodePack.sharedTables

DecodePack 顶层可声明 sharedTables,供所有 tokenDecoder.stepsmap / takeLongest 复用。查表顺序为“共享表 + 当前 tokenDecoder.tables”,同名时当前规则内的本地表覆盖共享表。

适合放进 sharedTables 的内容:

  • 跨产品线复用的工艺、die、controller profile。
  • 多个 PN / Flash ID / MPTool 规则都需要引用的 key-value 表。
  • 实际参与规则推导的匹配信息,例如 firmware_matchdie_mark。来源 URL、reference metadata 和可信度等维护证据只放入 evidence manifest,不进入共享表;尚未接线的既有 decode mapping 不因证据清理而删除。

table 形态

tables 的单张表支持三种写法,maptakeLongest 都会先归一化后再查询:

  • 普通 object 表:{ "AB": { "package": "FBGA-78" } },适合每个 key 有独立 value 的场景。
  • identity 数组表:["AB", "CD"],等价于 { "AB": "AB", "CD": "CD" },适合 token 白名单 / 最长前缀匹配,不需要再写 "AB": "AB" 这类重复映射。
  • alias-entry 数组表:[{ "keys": ["AB", "CD"], "value": { "package": "FBGA-78" } }],适合多个 token 共享同一个结构化 value。value 省略时,每个 key 仍按 identity 输出自身。

数组表中的 key 不应重复;pnpm cli decodepack check 会报告重复 key,避免后写项静默覆盖前写项。

nand.die_profile

nand.die_profile 是最重要的共享表之一。它以 die codename、firmware full code 或规则归一化后的 profile key 为索引,让 PN / Flash ID / MPTool 规则可以 cross-reference 出以下公开字段:

  • die_codename
  • process_alias
  • layer_count
  • die_density
  • cell_level
  • plane_count

公开结果中 die_codename 的 label 是 Process / 制程,它是用户可见制程名,不等同于内部 profile key:

  • 2D NAND 优先显示 15nmA19nm20nm 这类 litho。
  • Kioxia / SanDisk 3D NAND 显示 BiCS3BiCS4BiCS4.5,不带厂商前缀或 Cell 后缀。
  • 规则和共享表直接使用唯一的字段归属;已由 die_codename 完整表达的同一代际不再另写。独立的 generation_info / series_info 必须保留,不依赖结果生成器按字段存在与否隐藏信息。
  • 层数和 X3-90608T23 这类代号分别由 layer_count / process_alias 表达。
  • firmware_match / die_mark 只作为匹配和维护 metadata,不默认进入公开 fields。
  • 当 PN / Flash ID 规则需要给生成工具提供精确工艺关系时,应由规则显式输出 meta.nandDieProfileKeymeta.nandDieProfileKeys。compiler 不会根据公开 fields.* 自动反推该 metadata。

详细 key 命名、fallback profile 和厂商差异见 NAND Die Profile 标准化

profile key 维护边界

  • Kioxia / SanDisk 2D 固件匹配先归一为 2DM / 2DT
  • Kioxia / SanDisk BiCS profile key 必须带厂商前缀,例如 KBiCS3 / SBiCS3;firmware full code profile key 也必须带厂商前缀,例如 K7T23 / S7T23
  • Micron / Intel 3D 固件匹配直接使用 die codename,例如 B16A
  • IMFT / Solidigm FG 体系保留 A/B/C/D/E 等后缀 die codename,例如 N38AN38BN38CN38EN4PA
  • Micron RG 体系保留 R/S/T 等后缀 die codename,例如 B47RB57TN58R
  • 3D profile 不从后缀折叠为 xxnm;2D 5x/6x/7x/8x/9x die codename 可作为匹配 key,但公开制程应由 profile 表补齐。
  • YMTC PN 规则先把 PN token 组合映射到 TAS / HUS / WDS 这类 die profile key,再 cross-reference nand.die_profile 生成公开 profile 字段。

assign 表达式(DecodeExpr)

assign 的 value 允许:

  • 原始 JSON(字符串/数字/布尔/null/对象/数组)
  • { "$var": "name" }:从上下文读取变量
  • { "$tpl": "..." }:模板字符串替换 {{var}}{{obj.key}}(用于 URL、拼 key 等)
  • { "$path": "obj.key" }{ "$path": ["obj", "key"] }:读取上下文对象内的嵌套字段

当 PN 规则已经把 token 归一化成 nand.die_profile key(常见变量名如 processNode / processKey)时,直接复用该 key 输出 metadata:

{
  "op": "map",
  "from": "processNode",
  "table": "nand.die_profile",
  "to": "processObj",
  "default": {}
}
{
  "fields.die_codename": { "$var": "processNode" },
  "meta.nandDieProfileKey": { "$var": "processNode" }
}

takeLongest 可设置 keyTo,在输入本身不是已有 profile key、需要捕获命中的表 key 时再把 key 写入上下文变量。

Identifier DecodePack 的 bitfield definition 也可以直接使用 meta.nandDieProfileKeymeta.nandDieProfileKeys 作为输出 key;如果该值已经由同一个 definition 解出,应使用 {"from": "die_codename"} 复用已有输出,避免复制同一张 bitfield 表。这个 from 仍然是 DecodePack 显式声明,不是 compiler 自动从公开字段反推 metadata。

上下文默认提供:

  • partNumber: 归一化后的原始输入
  • rest: 当前未消费的字符串
  • 每一步 steps 写入的变量

Native draft 输出

{
  "assign": {
    "device.partNumber": { "$var": "partNumber" },
    "device.domain": "memory",
    "device.vendor": "biwin",
    "device.chipKind": "managed_nand",
    "device.productType": "emcp",
    "fields.density": { "$var": "density" },
    "fields.storage_interface": { "$path": "densityKeyObj.storage_interface" },
    "fields.dram_density": { "$path": "densityKeyObj.dram_density" },
    "components": [
      {
        "role": "dram",
        "device": { "domain": "memory", "chipKind": "dram", "productType": "lpddr4x" },
        "fields": { "dram_density": { "$path": "densityKeyObj.dram_density" } }
      }
    ],
    "meta.ruleId": "vendor.biwin.emcp.v1",
    "meta.fieldProfile": "managed_nand",
    "meta.capabilities": ["part.decode", "part.search"]
  }
}

约束:

  • assign 必须输出 fdnext-native draft,不再输出旧 FD 形态的扁平顶层字段。
  • fields.* 必须使用 packages/core/src/field-registry.ts 中的 canonical key。
  • 可信度、来源、reference status 等维护信息统一放入 docs/pn_code/evidence/decodepack-references.json 或 PN 文档,不能进入 DecodePack 内部表、fields 或公开 result。
  • composite 产品(例如 eMCP/uMCP)应使用 components 表达 storage / DRAM 子组件,不新增产品专属 public key。

3. Steps 操作符(op)

以下是当前 tokenDecoder.steps 支持的 op(与实现保持一致):

  • take: 从 rest 取固定长度
    • 参数:len, to
    • 行为:若 rest.length < len,则 to="",且不消耗 rest
  • map: 表映射
    • 参数:from, table, to, default
    • 行为:tables[table][context[from]] 存在则赋值,否则使用 defaulttables 包含顶层 sharedTables 与当前 tokenDecoder.tables,并支持 object / identity 数组 / alias-entry 数组三种表形态
  • takeLongest: 最长前缀匹配 + 消费
    • 参数:table, to, default,可选 scope, scopeSeparator
    • 行为:对 tables[table] 的 key 按长度降序匹配 rest 开头,匹配成功会消耗相应长度并写入值;tables 同样包含顶层 sharedTables 与当前 tokenDecoder.tables,并支持 object / identity 数组 / alias-entry 数组三种表形态;如设置 scope,会先按 ${scope}${scopeSeparator ?? ":"}${token} 形式匹配 scoped key,未命中时再回退到普通 key
  • stripIfPrefix: 条件剥离前缀
    • 参数:prefix, 可选 to
    • 行为:若 restprefix 开头则剥离;如提供 to 则写入布尔值(是否剥离成功)
  • tpl: 生成模板字符串
    • 参数:template, to
    • 行为:替换 {{var}} / {{obj.key}} 为对应上下文值(缺失则为空串)
  • fallback: 兜底选择
    • 参数:primary, secondary, to
    • 行为:若 primary 未定义/为 null/为空字符串,则取 secondary
  • mul: 乘法(用于密度等派生字段)
    • 参数:a, b, to, 可选 default
    • 行为:Number(context[a]) * Number(context[b]),非法则使用 default 或 0
  • dieDensity: 单 die 容量派生
    • 参数:density, dieCount, to, 可选 default
    • 行为:density 为正有限 Mbit 数值,dieCount 为正整数时返回 density / dieCount 的 Mbit 数值,例如 262144 / 1 -> 2621441048576 / 2 -> 524288;保留数值精度,不生成容量字符串。非法输入使用数值 default0。以该结果组成 lookup key 时同样使用 Mbit 数值。
  • set: 设置上下文常量(通常用于初始化对象)
    • 参数:to, value
  • merge: 合并对象(浅拷贝)
    • 参数:into, from
    • 行为:当两者都是“非数组对象”时 Object.assign(into, from)
  • notEmpty: 判断字符串非空
    • 参数:from, to
    • 行为:to = String(context[from]).length > 0
  • mergeIf: 条件合并
    • 参数:if, into, from
    • 行为:当 context[if] 为真且两者都是“非数组对象”时合并

4. 输出字段与翻译约定

iTXTech fdnext DecodePack 的 assign 应输出 core 的 native decoder draft(未翻译前)。公开结果由 @itxtech/fdnext-core 的 fdnext result builder 统一生成:

  • device 承载 vendor、chip kind、product type、PN / identifier / marking 等身份信息;这些身份字段不再复制到 blocks
  • decode 结果提供 subtitle 作为列表/详情页的简短摘要,格式由 result builder 根据 chip kind、vendor、容量、cell level、DRAM 组合等字段生成。
  • blocks 使用 canonical key 和结构化对象;可跳转能力放在对应 relations[].action,不再输出独立的顶层 actions[]
  • label / display / warning message / block label 由 field registry 与语言包生成,调用方不应从翻译文本反推语义。
  • 未知字段直接省略,不补旧响应里的 Unknown、空数组或 NAND-only 默认槽位。

重要约定:

  • fields.*components[].fields.* 中会进入公开结果的字段应使用 canonical snake_case key(例如 operation_temperaturespeed_gradestorage_interface),不要直接写 “Operation Temperature” 这类展示字符串。marking_code 等身份信息由 device 承载,不复制进详情字段。
  • PN / identifier iTXTech fdnext DecodePack 规则源文件必须使用 canonical snake_case 输出 key;运行时不维护历史 camelCase alias,也不做旧 key 自动转换。
  • 公开 package 使用 TYPE[-PIN][, DIM][, SPECIAL]。PIN 缺失时保留 TYPE,不得补猜;TYPE 缺失但 DIM 确认时只输出 DIM;未知 package 直接省略,不输出 Unknown,也不要在值里保留 mmballpin 等单位词。
  • standalone DRAM 的默认 topology 使用内部三态证明:已确认的公开 package 默认允许补 dram_die_count=1,plain DDR 还允许补 cs_count=1;当厂商 die/CS token 与公开 package 的来源不同,规则必须通过 meta.dramTopologyTokenRecognized 显式覆盖。true 表示 token 已识别但可以没有公开 package,false 表示 topology token 未知,即使其他 token 已能输出 package 也不得补默认值。这个 metadata 不进入公开 result。
  • 新增或重命名 metadata key 时,直接迁移全部 iTXTech fdnext DecodePack 源规则、语言包和测试。旧 key 应进入 packages/core/test/decodepack/metadata-audit.test.ts 的禁止列表,而不是进入兼容层。
  • 外部链接不要从 iTXTech fdnext DecodePack 直接泄漏到公开结果;平台侧应通过 runtime 的 External Link provider 输出到正式 links contract。

5. Pack 组织方式

推荐按厂商和芯片/产品线把 DecodePack JSON specs 放到单独 pack 文件(JSON 数组),例如 samsung-ufs-token.json,避免一个厂商的全部产品共用一个 pack:

  • 目录:packages/core/src/decodepack/rules/packs
  • 接入:packages/core/src/decodepack/rules/default-rules.ts:1

源码里用 JSON module 直接导入:

import rules from "./packs/xxx.json" with { type: "json" };

仓库 tsconfig 已开启 resolveJsonModule,并且打包器配置了 .json loader。

6. 如何新增/验证一个厂商解码器

  • 新增厂商或整盘/模组 decoder 的授权范围见根目录 AGENTS.md;已有产品线维护按当前任务继续。
  • 新增 pack:packages/core/src/decodepack/rules/packs/<vendor>-<product>-token.json
  • default-rules.ts 中导入并加入 defaultPartDecodeSpecs
  • packages/core/test/decodepack/dram/part-number/ 添加必要的产品线行为测试,并同步厂商文档和证据。
  • 单一 pack 执行 DecodePack 检查、定向测试和 core typecheck;影响共享逻辑或跨包 contract 时再按 验证指南 扩大范围。

7. 维护工具

DecodePack 维护工具面向 AI 和人工 review,既可通过 TypeScript API 调用,也可通过 CLI 使用。

import {
  checkDecodePack,
  compileDecodePack,
  type DecodePack,
  defaultDecodePack,
  explainPartDecode,
  validateDecodePack
} from "@itxtech/fdnext-core/decodepack";

const check = checkDecodePack(defaultDecodePack);
const compiled = compileDecodePack(defaultDecodePack);
const explain = explainPartDecode(defaultDecodePack, "BWCA2KZC-64G");

// 自定义 pack 必须先通过校验;validate 会冻结 pack,compiler 只接受 branded 结果。
const compileCustomPack = (pack: DecodePack) => compileDecodePack(validateDecodePack(pack));

仓库内 CLI:

pnpm cli decodepack check
pnpm cli decodepack explain part BWCA2KZC-64G
pnpm cli decodepack explain id 2C64444BA900

发布 / 全局安装后的二进制仍是 fdnext decodepack ...

7.1 按目标字段投影解码

编译后的 PN decoder 支持运行时传入任意 draft path,而不是绑定固定的“搜索字段集”:

for (const decoder of compiled.partDecoders) {
  const match = decoder.match(partNumber);
  if (!match) continue;
  const summary = decoder.project?.(match, [
    "device.vendor",
    "fields.density",
    "fields.package"
  ]);
  break;
}

compiler 会按 assign 表达式反向追踪变量依赖,为每组 target path 缓存执行计划;无关 step 不执行,并在最后一个必要 step 后停止。目标字段的值必须与完整 decode() 一致。投影结果会保留 device.partNumber,也可能带有计算目标所需的附加依赖字段,调用方不应把“未请求字段一定不存在”作为 contract。

搜索层当前所需字段由 DEFAULT_PART_SEARCH_PROJECTION 声明;后续结果 contract 或排序逻辑新增字段时,可通过 createEngine({ partSearchProjection: [...] }) 追加 target path,无需修改 compiler 或新增固定 profile。

8. Identifier iTXTech fdnext DecodePack(NAND Flash ID 概览)

NAND Flash ID 解码通过 typed identifier iTXTech fdnext DecodePack 表达,规则必须声明 idScheme: "nand.flash_id"。输入仍按“字节偏移 + bitfield 规则”描述,并编译为 IdentifierDecoder

8.1 Pack 位置

  • Identifier packs:packages/core/src/decodepack/identifier/packs/*.json
  • 接入入口:packages/core/src/decodepack/identifier/default-rules.ts:1

源码里同样用 JSON module 直接导入:

import rules from "./packs/xxx.json" with { type: "json" };

8.2 IdentifierDecodeSpec 结构

每个 pack 文件是一个 JSON 数组,元素结构如下:

{
  "id": "flashid.micron.v1",
  "idScheme": "nand.flash_id",
  "priority": 400,
  "match": { "kind": "prefix", "value": "2C" },
  "vendor": "micron",
  "definition": {
    "2": {
      "density": { "dq": [7, 6, 5, 4, 3], "def": { "9": 32768 } }
    }
  }
}

字段说明:

  • id: spec 唯一标识;内置 Flash ID spec 统一使用 flashid.<vendor>[.<family-or-profile>].vN
  • idScheme: identifier namespace,目前 NAND Flash ID 使用 nand.flash_id
  • priority: 优先级(越大越优先)
  • match: 匹配 identifier(支持 prefix / regex
  • vendor: 厂商 key(用于语言包翻译与展示)
  • definition: bitfield spec 定义

内置 Flash ID spec 的 vendor 段必须与 vendor 字段一致;层级使用 .,复合词使用 -,不使用 _identifiernand_flash_idparallel 等已由模块和 idScheme 表达的信息不再重复写入 id

8.3 definition(字节偏移 + bitfield)

  • definition 的第一层 key 是 字节偏移(字符串数字),并且是 1-based
    • 例如 "1" 表示第 1 个字节(厂商 ID),"2" 表示第 2 个字节。
  • 输入 NAND Flash ID 以 12 个 hex 字符(6 字节)为基准;不足会由 core 的内部 NAND Flash ID decoder 在末尾补 0
  • 每个字段由:
    • dq: bit 位列表,按 spec 定义顺序拼接
    • def: 从 bitfield 数值(字符串)映射到输出值(number/string/bool)
    • 可选 when: 按 1-based 字节偏移限制 rule,例如 { "2": ["05", "09"] }
  • 字段名直接使用 canonical field key(例如 interface_typetiming_mode_asyncecc_level)。
  • 同一字段可以写成 rule 数组,编译器会按顺序使用第一个 when 命中且 def 可解析的 rule。常见用途是先放完整字节精确表,再回落到旧的 bitfield 规则。

8.4 NAND Flash ID 后处理(core 内置)

部分 NAND Flash ID 需要“解码后再修正”的逻辑,无法用纯 bitfield iTXTech fdnext DecodePack 表达,因此在 @itxtech/fdnext-core 内置了 NAND Flash ID post-process:

  • Samsung:当 byte2 == 0xDE,密度强制为 64Gbit
  • SKHynix:plane_count = simultaneously_programmed_pages
  • SKHynix:当 byte6 >= 0x50(14nm+)清理不适用的 timing/interface/ECC 细节字段
  • Kioxia / WesternDigital:当 plane_countdie_count 都有效时,plane_count = plane_count / die_count

8.5 如何新增/验证 NAND Flash ID 解码器

  • 新增厂商需符合根目录 AGENTS.md 的授权范围。
  • 新增 pack:packages/core/src/decodepack/identifier/packs/<vendor>.json
  • packages/core/src/decodepack/identifier/default-rules.ts:1 中导入并加入 defaultIdentifierDecodeSpecs
  • 在对应 identifier 测试中覆盖改变的行为;只有跨包 contract 行为改变时才更新相应 contract testcase。
  • 单一 pack 使用 DecodePack 检查、定向测试和 core typecheck;编译器或共享后处理变化按 验证指南 运行 core 全量,跨包消费面变化再做 contract 检查。