Rust in Everything
基于 target-gen 0.32.0

target-gen 与 CMSIS-Pack

主线位置:命令主线之外,目标描述的来源。内置的 242 个 YAML 里有 125 个家族标着 generated_from_pack: true,是工作区里的 target-gen 从芯片厂商发布的 CMSIS-Pack 转出来的。本页按源码讲它怎么转;本机没有装 target-gen,也不联网下载 pack,所以没有实际跑。

flowchart TB
  pack["CMSIS-Pack:.pack 是一个 zip"] --> pdsc[".pdsc:XML,器件、处理器、内存、算法"]
  pdsc --> dev["每个 device"]
  dev --> cores["processor:Cortex-M 型号变成 CoreType,AP 号"]
  dev --> mem["memory:变成 Ram、Nvm 区"]
  dev --> algo[".FLM:flash 算法 ELF"]
  algo --> fd["符号 FlashDevice:名字、地址、页大小、扇区表"]
  algo --> blob["PrgCode、PrgData 段:拼成一段指令"]
  algo --> syms["符号 Init、EraseSector、ProgramPage 等:入口偏移"]
  cores --> fam["ChipFamily:算法按名字去重"]
  mem --> fam
  fd --> fam
  blob --> fam
  syms --> fam
  fam --> yaml["serialize_to_yaml_string:写 YAML"]

五个子命令

target-gen/src/main.rs 的 TargetGen 枚举:

子命令输入干什么要硬件 / 网络吗
pack一个 .pack 文件或解开的目录生成该 pack 里所有家族的 YAML都不要
arm可选的 --filter从 ARM 的索引下载 pack 再生成;不给过滤条件时只处理 probe-rs 已支持的家族要网络(fetch.rs 用 reqwest 取 https://www.keil.com/pack/index.pidx;子命令的帮助文字写的是 Keil.pidx,和代码不一致)
elf自己编译的 flash 算法 ELF抽出一个 RawFlashAlgorithm,可以更新已有 YAML都不要
test模板 YAML、ELF生成 YAML 后在接着的板子上实际擦写一遍,可当 cargo runner要探针
reformatYAML 文件或目录读进来再按规范格式写回都不要

main 第一行同样注册了 ESP 插件,所以 target-gen 也依赖 probe-rs-espressif(源码地图)。

pack:从 pdsc 到 ChipFamily

visit_file 把 .pack 当 zip 打开,找到里面的 .pdsc,用 cmsis-pack crate 解析成 Package,再交给 extract_families。后者对每个器件(generate.rs:71):

  1. 按 pdsc 里的 family 名找或新建一个 ChipFamily,generated_from_pack: true,pack_file_release 记 pack 的最新版本号。
  2. 处理器变成核:core_to_probe_core 是一张表,M0 / M0+ → Armv6m,M3 → Armv7m,M4 / M7 → Armv7em,M23 / M33 / M55 / M85 / STAR-MC1 → Armv8m,其他核报「not yet supported」。注意 M23 是基线 Armv8-M,在这里和 M33 归成同一种核类型,和 Cortex-M 内核里 armv8m.rs 固定 main = true 是同一个问题的两端。AP 号按 pdsc 的写法变成 !v1 n 或 !v2 地址;targetsel、jtag 一律不填(源码 TODO:「parse scan chain from sdf」),所以 RP2040 这种多点 SWD 芯片的 YAML 是手写的。
  3. 内存变成 Ram / Nvm 区,再打几个补丁(比如只有一个 RAM 区时确保它可执行,flash 算法要在里面跑)。
  4. 每个算法文件交给 process_flash_algo,结果按内容去重后放进家族的 flash_algorithms,型号只记名字。pdsc 给了 RAMstart 时,把它加上算法头的最大长度作为固定加载地址。

一个细节:只处理已支持家族(arm 子命令不带过滤条件时)的分支,遇到第一个不认识的家族写的是 return Ok(()),而不是 continue;注释说「Skipping ...」,但从代码看,同一个 pack 里排在它后面(器件按名字排序)的器件也都不会处理。pack 子命令传的是 false,不受影响。实际影响未核实。

flash 算法 ELF 里有什么

CMSIS 的 flash 算法(.FLM)是一个普通的 ELF,约定是:

  • 一个叫 FlashDevice 的全局结构,160 字节加一张扇区表。FlashDevice::new 按固定偏移读:偏移 2 起 128 字节是名字,132 是起始地址,136 是大小,140 是页大小,148 是擦除后的字节值,152、156 是编程和擦除超时;之后每 8 字节一项 (扇区大小, 起始偏移),直到读到 0xFFFFFFFF 结束标记。
  • 代码在 PrgCode 段,数据在 PrgData 段(.bss 也叫 PrgData,类型是 NOBITS)。AlgorithmBinary 按 PT_LOAD 段把它们拼成一段连续的字节,就是 YAML 里那串 base64 的 instructions。
  • 函数入口是符号:Init、UnInit、EraseChip、EraseSector、ProgramPage、Verify、BlankCheck。probe-rs 另外认 ReadFlash、_SEGGER_RTT(算法里的 RTT 控制块,flash 算法的 --read-flasher-rtt 用它)、PAGE_BUFFER(固定的页缓冲区地址),以及 0.32 新加的 VendorFunc_ 前缀(#3989):VendorFunc_read_flash_size 变成 vendor_functions 里的 read_flash_size,取代了以前专门为 ESP32 硬编码的那个函数。

extract_flash_algo 把符号地址减去代码段的起点,得到相对偏移。STM32F1 的算法生成出来是这样:

# probe-rs/targets/STM32F1_Series.yaml
- name: stm32f10x_128
  description: STM32F10x Med-density Flash
  default: true
  instructions: ELUDRgAgREwgYERIYGBESGBgIEbAaRDwBA8I0UXyVVBATCBgBiBgYED2/3Cg...
  pc_init: 0x1
  pc_uninit: 0x33
  pc_program_page: 0xbd
  pc_erase_sector: 0x7f
  pc_erase_all: 0x45
  data_section_offset: 0x128
  flash_properties:
    address_range:
      start: 0x8000000
      end: 0x8020000
    page_size: 0x400
    erased_byte_value: 0xff
    program_page_timeout: 100
    erase_sector_timeout: 500
    sectors:
    - size: 0x400
      address: 0x0

pc_init: 0x1 的最低位是 Thumb 位。下一部分的实验里,probe-rs 把这段代码装到 0x20000000,前面加 4 字节的断点头,于是 Init 的地址是 0x20000004 + 0x1 = 0x20000005,static_base 是 0x20000004 + 0x128 = 0x2000012c,和这里的偏移对得上(从镜像到烧录计划、flash 算法)。

elf:自己写的算法

厂商没有提供 CMSIS 算法、或者想用 Rust 重写一个更快的算法时,用 target-gen elf:它对一个自己编译的 ELF 走同样的 extract_flash_algo。加 --fixed-load-address 时要求代码、数据段在 RAM 里首尾相接,并把链接地址记成 load_address;否则当作位置无关代码,加载地址由 probe-rs 在烧录时选。cmd_elf 还会把结果和已有 YAML 里的算法合并、压缩重复项。写好之后用 test 子命令在真板子上擦写验证,这一步待实测。

小结

  • target-gen 从 CMSIS-Pack 的 pdsc 里抽器件、核、内存和算法,生成 probe-rs 的 YAML;内置 242 个 YAML 中 125 个家族由它生成。
  • 核类型靠一张 Cortex-M 型号表,M23 被归为 Armv8m;targetsel、JTAG 扫描链不从 pack 里取,多点 SWD 芯片的 YAML 要手写。
  • flash 算法 ELF 的约定:FlashDevice 结构给几何参数,PrgCode / PrgData 段拼成指令,Init / EraseSector / ProgramPage 等符号给入口偏移;probe-rs 另认 _SEGGER_RTT、PAGE_BUFFER、VendorFunc_*。
  • pack、elf、reformat 离线可用,arm 要联网,test 要硬件。

💬 关联讨论

发起讨论
加载中...