tan-cli 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (330) hide show
  1. tan/__init__.py +0 -0
  2. tan/__main__.py +120 -0
  3. tan/cli.py +939 -0
  4. tan/command_table.py +265 -0
  5. tan/commands/__init__.py +8 -0
  6. tan/commands/bootstrap_cmd.py +4856 -0
  7. tan/commands/bootstrap_patches.py +164 -0
  8. tan/commands/bootstrap_toolchain_fetch.py +155 -0
  9. tan/commands/bootstrap_toolchain_pin.py +36 -0
  10. tan/commands/build/__init__.py +1 -0
  11. tan/commands/build/configure_inputs.py +277 -0
  12. tan/commands/build/execute.py +1852 -0
  13. tan/commands/build/host_python.py +59 -0
  14. tan/commands/build/link_stale.py +78 -0
  15. tan/commands/build/manifest.py +428 -0
  16. tan/commands/build/materialise.py +81 -0
  17. tan/commands/build/token_substitution.py +381 -0
  18. tan/commands/build/toolchain.py +482 -0
  19. tan/commands/build/user_defines_wipe.py +115 -0
  20. tan/commands/build/workspace_patches.py +65 -0
  21. tan/commands/build_cmd.py +2236 -0
  22. tan/commands/build_output.py +331 -0
  23. tan/commands/clean_cmd.py +1183 -0
  24. tan/commands/completion_cmd.py +786 -0
  25. tan/commands/debug_config_cmd.py +2425 -0
  26. tan/commands/diff_cmd.py +940 -0
  27. tan/commands/doctor_cmd.py +4767 -0
  28. tan/commands/examples_cmd.py +644 -0
  29. tan/commands/explain_cmd.py +1319 -0
  30. tan/commands/faultdecode_cmd.py +931 -0
  31. tan/commands/flash_atoc_guard.py +240 -0
  32. tan/commands/flash_cmd.py +5731 -0
  33. tan/commands/flash_mram_guard.py +150 -0
  34. tan/commands/flash_ram.py +578 -0
  35. tan/commands/flash_raw.py +583 -0
  36. tan/commands/generate_cmd.py +1456 -0
  37. tan/commands/image_cmd.py +753 -0
  38. tan/commands/init_cmd.py +1740 -0
  39. tan/commands/inspect_cmd.py +377 -0
  40. tan/commands/kconfig_cmd.py +734 -0
  41. tan/commands/model_cmd.py +1514 -0
  42. tan/commands/model_device_cmd.py +351 -0
  43. tan/commands/model_device_live.py +234 -0
  44. tan/commands/model_host_cmd.py +430 -0
  45. tan/commands/model_zoo_cmd.py +363 -0
  46. tan/commands/monitor_actions.py +125 -0
  47. tan/commands/monitor_cmd.py +626 -0
  48. tan/commands/monitor_session.py +505 -0
  49. tan/commands/new_som_cmd.py +1522 -0
  50. tan/commands/pinmux_cmd.py +568 -0
  51. tan/commands/presets_cmd.py +1123 -0
  52. tan/commands/probe_cmd.py +421 -0
  53. tan/commands/reset_cmd.py +354 -0
  54. tan/commands/reset_confirm.py +168 -0
  55. tan/commands/run_cmd.py +637 -0
  56. tan/commands/scaffold_cmd.py +490 -0
  57. tan/commands/sdk_cmd.py +1723 -0
  58. tan/commands/size_cmd.py +1020 -0
  59. tan/commands/support_bundle_cmd.py +1073 -0
  60. tan/commands/trace_cmd.py +341 -0
  61. tan/commands/validate_cmd.py +2009 -0
  62. tan/commands/west_forward_cmd.py +736 -0
  63. tan/commands/workspace_patch_check.py +296 -0
  64. tan/core/__init__.py +1 -0
  65. tan/core/alp_conf_pregen.py +100 -0
  66. tan/core/artifact_provenance.py +240 -0
  67. tan/core/atoc_guard.py +276 -0
  68. tan/core/atoc_guard_messages.py +232 -0
  69. tan/core/atoc_replacement.py +118 -0
  70. tan/core/atomic_write.py +178 -0
  71. tan/core/board_context.py +351 -0
  72. tan/core/board_diagnostic.py +111 -0
  73. tan/core/board_files.py +221 -0
  74. tan/core/board_validator.py +542 -0
  75. tan/core/board_validator_compat.py +196 -0
  76. tan/core/board_validator_run.py +129 -0
  77. tan/core/board_validator_schema.py +186 -0
  78. tan/core/board_validator_skew.py +46 -0
  79. tan/core/board_yaml_edit.py +295 -0
  80. tan/core/board_yaml_pos.py +118 -0
  81. tan/core/bootstrap.py +2572 -0
  82. tan/core/build_plan.py +625 -0
  83. tan/core/consent.py +104 -0
  84. tan/core/console_filter.py +245 -0
  85. tan/core/debug_launch.py +1803 -0
  86. tan/core/devicetree_lint.py +168 -0
  87. tan/core/dir_removal.py +229 -0
  88. tan/core/doctor_git.py +172 -0
  89. tan/core/doctor_libraries.py +253 -0
  90. tan/core/doctor_render.py +185 -0
  91. tan/core/doctor_scope.py +66 -0
  92. tan/core/doctor_setools.py +237 -0
  93. tan/core/doctor_stale.py +180 -0
  94. tan/core/document_guards.py +723 -0
  95. tan/core/dp_id.py +97 -0
  96. tan/core/elf_load.py +63 -0
  97. tan/core/error_catalog.py +171 -0
  98. tan/core/example_catalog.py +499 -0
  99. tan/core/example_facets.py +151 -0
  100. tan/core/faultdecode.py +521 -0
  101. tan/core/flash_plan.py +2501 -0
  102. tan/core/flow_d_report.py +381 -0
  103. tan/core/flow_d_uptime.py +164 -0
  104. tan/core/fs_confine.py +130 -0
  105. tan/core/global_flags.py +230 -0
  106. tan/core/host_python.py +210 -0
  107. tan/core/image_bundle.py +247 -0
  108. tan/core/inert.py +147 -0
  109. tan/core/jlink_binary.py +128 -0
  110. tan/core/jlink_probe.py +481 -0
  111. tan/core/jsonc_splice.py +404 -0
  112. tan/core/launch_provenance.py +257 -0
  113. tan/core/link_refusal.py +76 -0
  114. tan/core/metadata_schema.py +376 -0
  115. tan/core/model_check.py +227 -0
  116. tan/core/model_device.py +449 -0
  117. tan/core/model_doctor.py +198 -0
  118. tan/core/model_host.py +48 -0
  119. tan/core/model_list.py +112 -0
  120. tan/core/model_zoo.py +353 -0
  121. tan/core/module_template.py +340 -0
  122. tan/core/mram_link.py +87 -0
  123. tan/core/new_som_ospi.py +94 -0
  124. tan/core/os_class.py +159 -0
  125. tan/core/patch_paths.py +87 -0
  126. tan/core/pending.py +40 -0
  127. tan/core/plain_zephyr_plan.py +138 -0
  128. tan/core/plan_exec.py +373 -0
  129. tan/core/plan_tokens.py +600 -0
  130. tan/core/probe.py +155 -0
  131. tan/core/probe_plan.py +237 -0
  132. tan/core/proxy.py +168 -0
  133. tan/core/publish.py +31 -0
  134. tan/core/python_floor.py +178 -0
  135. tan/core/ram_run.py +694 -0
  136. tan/core/ram_watch.py +231 -0
  137. tan/core/raw_write.py +160 -0
  138. tan/core/reset_plan.py +56 -0
  139. tan/core/run.py +161 -0
  140. tan/core/scaffold.py +2203 -0
  141. tan/core/scaffold_selftest_identity.py +225 -0
  142. tan/core/sdk_default_registry.py +565 -0
  143. tan/core/sdk_discovery.py +996 -0
  144. tan/core/sdk_removal.py +465 -0
  145. tan/core/serial_actions.py +175 -0
  146. tan/core/serial_capture.py +185 -0
  147. tan/core/serial_url.py +45 -0
  148. tan/core/setools.py +608 -0
  149. tan/core/setools_scratch.py +243 -0
  150. tan/core/shapes.py +194 -0
  151. tan/core/size.py +610 -0
  152. tan/core/som_buildability.py +204 -0
  153. tan/core/som_schema_version.py +62 -0
  154. tan/core/subprocess_env.py +201 -0
  155. tan/core/sysbuild_image.py +94 -0
  156. tan/core/system_manifest.py +827 -0
  157. tan/core/text_layout.py +73 -0
  158. tan/core/timestamp.py +182 -0
  159. tan/core/tool_lookup.py +383 -0
  160. tan/core/toolchain_pin.py +117 -0
  161. tan/core/toolchain_provision.py +1224 -0
  162. tan/core/trusted_path.py +134 -0
  163. tan/core/uboot_breakin.py +154 -0
  164. tan/core/uri_reference.py +415 -0
  165. tan/core/user_defines.py +152 -0
  166. tan/core/venv.py +332 -0
  167. tan/core/west_patches.py +143 -0
  168. tan/core/west_workspace_refusal.py +159 -0
  169. tan/core/zephyr_env.py +124 -0
  170. tan/env.py +185 -0
  171. tan/envelope.py +647 -0
  172. tan/exit_codes.py +12 -0
  173. tan/lazy_typer.py +185 -0
  174. tan/model/__init__.py +2 -0
  175. tan/model/_gen_fixture.py +132 -0
  176. tan/model/adapters/__init__.py +116 -0
  177. tan/model/adapters/cpu.py +26 -0
  178. tan/model/adapters/deepx.py +94 -0
  179. tan/model/adapters/drpai.py +242 -0
  180. tan/model/adapters/ethos_u.py +951 -0
  181. tan/model/adapters/executorch.py +55 -0
  182. tan/model/analyze.py +694 -0
  183. tan/model/build.py +304 -0
  184. tan/model/check.py +682 -0
  185. tan/model/manifest.py +625 -0
  186. tan/model/measure.py +216 -0
  187. tan/model/npu_ops_validate.py +130 -0
  188. tan/model/package.py +125 -0
  189. tan/model/perf.py +635 -0
  190. tan/model/perf_apply.py +721 -0
  191. tan/model/prep.py +193 -0
  192. tan/model/sram_fit.py +502 -0
  193. tan/model/targets.py +374 -0
  194. tan/model/tensorio.py +287 -0
  195. tan/net.py +73 -0
  196. tan/output_format.py +213 -0
  197. tan/planner/__init__.py +219 -0
  198. tan/planner/aperture.py +202 -0
  199. tan/planner/buildplan.py +1092 -0
  200. tan/planner/camera_owner.py +192 -0
  201. tan/planner/cameras.py +132 -0
  202. tan/planner/carveout.py +755 -0
  203. tan/planner/cli.py +274 -0
  204. tan/planner/headers.py +315 -0
  205. tan/planner/kconfig.py +2435 -0
  206. tan/planner/kconfig_symbols.py +473 -0
  207. tan/planner/libraries.py +677 -0
  208. tan/planner/link_target.py +237 -0
  209. tan/planner/linux_ownership.py +216 -0
  210. tan/planner/loader.py +1525 -0
  211. tan/planner/manifest.py +116 -0
  212. tan/planner/memory.py +161 -0
  213. tan/planner/memregion.py +56 -0
  214. tan/planner/models.py +533 -0
  215. tan/planner/orchestrator.py +874 -0
  216. tan/planner/ownership.py +203 -0
  217. tan/planner/partition.py +1160 -0
  218. tan/planner/paths.py +32 -0
  219. tan/planner/plain_slice.py +139 -0
  220. tan/planner/project_emit/__init__.py +60 -0
  221. tan/planner/project_emit/bom_netlist.py +375 -0
  222. tan/planner/project_emit/dts.py +580 -0
  223. tan/planner/project_emit/hw_info.py +221 -0
  224. tan/planner/project_emit/native_sim.py +136 -0
  225. tan/planner/project_emit/west_libs.py +213 -0
  226. tan/planner/project_loader.py +264 -0
  227. tan/planner/sdk_capability.py +203 -0
  228. tan/planner/sdk_compat.py +395 -0
  229. tan/planner/secure.py +350 -0
  230. tan/planner/slugs.py +394 -0
  231. tan/planner/som_metadata.py +325 -0
  232. tan/planner/strict_loaders.py +131 -0
  233. tan/planner/template.py +1037 -0
  234. tan/planner/template_pins.py +535 -0
  235. tan/planner/template_rewrite.py +714 -0
  236. tan/planner/topology.py +208 -0
  237. tan/planner/validate.py +365 -0
  238. tan/planner/whole_device_alias.py +67 -0
  239. tan/planner/zephyr_board.py +3510 -0
  240. tan/planner_cli.py +97 -0
  241. tan/planner_emit.py +617 -0
  242. tan/planner_root.py +119 -0
  243. tan/soc_ref.py +58 -0
  244. tan/templates/__init__.py +34 -0
  245. tan/templates/vendored/MANIFEST.md +1862 -0
  246. tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
  247. tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
  248. tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
  249. tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
  250. tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
  251. tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
  252. tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
  253. tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
  254. tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
  255. tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
  256. tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
  257. tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
  258. tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
  259. tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
  260. tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
  261. tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
  262. tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
  263. tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
  264. tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
  265. tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
  266. tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
  267. tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
  268. tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
  269. tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
  270. tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
  271. tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
  272. tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
  273. tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
  274. tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
  275. tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
  276. tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
  277. tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
  278. tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
  279. tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
  280. tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
  281. tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
  282. tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
  283. tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
  284. tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
  285. tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
  286. tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
  287. tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
  288. tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
  289. tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
  290. tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
  291. tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
  292. tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
  293. tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
  294. tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
  295. tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
  296. tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
  297. tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
  298. tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
  299. tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
  300. tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
  301. tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
  302. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
  303. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
  304. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
  305. tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
  306. tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
  307. tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
  308. tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
  309. tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
  310. tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
  311. tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
  312. tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
  313. tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
  314. tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
  315. tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
  316. tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
  317. tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
  318. tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
  319. tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
  320. tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
  321. tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
  322. tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
  323. tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
  324. tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
  325. tan/version.py +102 -0
  326. tan_cli-0.7.0.dist-info/METADATA +125 -0
  327. tan_cli-0.7.0.dist-info/RECORD +330 -0
  328. tan_cli-0.7.0.dist-info/WHEEL +5 -0
  329. tan_cli-0.7.0.dist-info/entry_points.txt +2 -0
  330. tan_cli-0.7.0.dist-info/top_level.txt +1 -0
tan/planner/slugs.py ADDED
@@ -0,0 +1,394 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """Kconfig / board-define slug derivation -- a shared leaf.
4
+
5
+ The slug + symbol helpers the per-slice config emitters (alp.conf, cmake-args)
6
+ share: the board-define slug, the on-module / helper-firmware Kconfig slug
7
+ derivation (+ the non-chip field set they skip), and the two Kconfig-mapping
8
+ tables (peripheral -> symbol bundle, chip -> subsystem dependency). A leaf that
9
+ reaches only for `paths`, so every per-slice emitter pulls them from one place
10
+ instead of duplicating. Extracted as a #285 leaf seam (the paths.py /
11
+ memregion.py move) ahead of the kconfig emitter.
12
+
13
+ `peripheral_kconfig` is RELOCATED from alp-sdk's `scripts/alp_registries.py` and
14
+ `_CHIP_SUBSYSTEMS` from `scripts/alp_project_emit/__init__.py` -- the last two
15
+ edges this leaf and `kconfig.py` made into the SDK's Python. The peripheral
16
+ table is still READ from the SDK's `metadata/registries/peripheral-kconfig.json`
17
+ (the fact stays there, ADR-0017); `_CHIP_SUBSYSTEMS` has no registry file to
18
+ read from today, so it moves with its one and only consumer -- see the note
19
+ above the table.
20
+
21
+ `peripheral_kconfig` used to be a module-level constant computed once at
22
+ import time from the SDK's own in-tree metadata/ -- a project's own
23
+ `--metadata-root` override never reached it (alp-sdk #1485). It now takes
24
+ *metadata_root* as a required argument; callers pass
25
+ `project.effective_metadata_root()` at the point of use.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import functools
31
+ import json
32
+ from pathlib import Path
33
+
34
+ from .paths import REPO
35
+
36
+
37
+ @functools.lru_cache(maxsize=None)
38
+ def peripheral_kconfig(metadata_root: Path) -> dict[str, tuple[str, ...]]:
39
+ """Return board.yaml peripheral tokens -> Zephyr Kconfig symbol bundles.
40
+
41
+ *metadata_root* is REQUIRED -- every caller must pass the project's own
42
+ ``project.effective_metadata_root()`` (or the SDK's own in-tree
43
+ ``METADATA_ROOT`` for a repo self-check). A module-level default here
44
+ is exactly the shape that let this registry silently ignore a project's
45
+ `--metadata-root` override (#1485); the cache is keyed on
46
+ *metadata_root* so a second root in the same process doesn't reuse the
47
+ first root's table.
48
+
49
+ The validation below is alp-sdk#1545's, re-rooted at *metadata_root*.
50
+ Upstream wrote it for two import-time callers; in tan the one caller is
51
+ `kconfig._emit_subsystems`, and it now reads the table at RENDER time
52
+ rather than at import (that is what #1485's move bought). A malformed
53
+ on-disk registry therefore lands here mid-render, where a raw
54
+ `JSONDecodeError`/`KeyError`/`AttributeError` would name neither the
55
+ file nor the problem -- and where `tan generate` turns an exception into
56
+ an envelope, so the message IS the diagnosis a customer gets. Raise a
57
+ `ValueError` naming the real problem instead.
58
+
59
+ A consequence tan owns and alp-sdk does not: `planner_emit.unavailable()`
60
+ measures in-process availability by IMPORTING `tan.planner`, so while
61
+ this table was a module constant, a checkout missing the registry
62
+ disabled the in-process engine for EVERY target. It no longer does --
63
+ only the emits that actually need the table fail, and they fail with the
64
+ message above (`tests/parity/test_planner_emit_parity.py::
65
+ test_a_fallback_on_an_incomplete_checkout_says_so` moved to a different
66
+ trigger for exactly this reason, tan-cli#868).
67
+ """
68
+ registry = Path(metadata_root) / "registries" / "peripheral-kconfig.json"
69
+ try:
70
+ rel = registry.relative_to(REPO).as_posix()
71
+ except ValueError:
72
+ # `metadata_root` legitimately points outside REPO (a scratch root
73
+ # under `--metadata-root`, or a test fixture) -- `relative_to()`
74
+ # raises its own confusing "is not in the subpath of" there, which
75
+ # would mask whatever the caller actually did wrong. Fall back to
76
+ # the raw path string.
77
+ rel = str(registry)
78
+ try:
79
+ text = registry.read_text(encoding="utf-8")
80
+ except OSError as e:
81
+ # A missing/unreadable file is not "invalid JSON" -- report the
82
+ # real failure instead of mislabeling every OSError that way.
83
+ raise ValueError(f"{rel}: cannot read registry ({e})") from e
84
+ try:
85
+ data = json.loads(text)
86
+ except json.JSONDecodeError as e:
87
+ raise ValueError(f"{rel}: invalid JSON ({e})") from e
88
+ if not isinstance(data, dict):
89
+ raise ValueError(
90
+ f"{rel}: expected a top-level object (got {type(data).__name__})")
91
+ if "peripherals" not in data:
92
+ raise ValueError(f"{rel}: missing top-level `peripherals` key")
93
+ peripherals = data["peripherals"]
94
+ if not isinstance(peripherals, dict):
95
+ raise ValueError(
96
+ f"{rel}: `peripherals` must be an object "
97
+ f"(got {type(peripherals).__name__})")
98
+ result: dict[str, tuple[str, ...]] = {}
99
+ for token, symbols in peripherals.items():
100
+ if not isinstance(symbols, list):
101
+ raise ValueError(
102
+ f"{rel}: peripherals[{token!r}] must be an array of "
103
+ f"Zephyr Kconfig symbols (got {type(symbols).__name__})")
104
+ result[token] = tuple(symbols)
105
+ return result
106
+
107
+
108
+ def _is_tbd(value: object) -> bool:
109
+ """Case/whitespace-insensitive `TBD` placeholder match ("tbd", "Tbd",
110
+ " TBD " all match, alp-sdk #1048) -- the two chip-slug extractors below
111
+ both used a bare `== "TBD"` before, so an all-lowercase board.yaml
112
+ value silently fell through as a real chip slug instead of being
113
+ dropped as the placeholder it was hand-typed to mean."""
114
+ return isinstance(value, str) and value.strip().upper() == "TBD"
115
+
116
+
117
+ def _board_define_slug(name: str) -> str:
118
+ """'E1M-X-EVK' -> 'E1M_X_EVK': the ALP_BOARD_* compile-define suffix.
119
+
120
+ Mirrors gen_board_header._board_slug (lower + '-'->'_') then uppercases
121
+ for the C macro. Used by <alp/board.h>'s board-selection facade.
122
+ """
123
+ return name.lower().replace("-", "_").upper()
124
+
125
+
126
+ def _som_define_slug(sku: str) -> str:
127
+ """'E1M-AEN801' -> 'E1M_AEN801': the ALP_SOM_* compile-define suffix.
128
+
129
+ Same transform as _board_define_slug; kept as its own name so the
130
+ SoM-selection define (per-SKU capability restrictions in
131
+ <alp/soc_caps.h>, gen_soc_caps.som_token) reads distinctly from the
132
+ board facade define at call sites.
133
+ """
134
+ return _board_define_slug(sku)
135
+
136
+
137
+ # on_module fields that carry non-chip-slug values — skip them when
138
+ # walking the block for chip-driver enables. Numeric fields, silicon
139
+ # identifiers, and structured sub-blocks are excluded by name rather
140
+ # than by type so the logic stays explicit and easy to audit.
141
+ _ON_MODULE_NON_CHIP_FIELDS: frozenset[str] = frozenset({
142
+ "silicon", # e.g. "renesas:rzv2n:n44" — SoC identifier, not a driver
143
+ "ethernet_phy_count", # integer count, not a chip slug
144
+ "i2c_devices", # sub-block: handled by extracting chip: entries below
145
+ "dxm1", # sub-block: DX-M1 strap/reset pins, not chip slugs
146
+ "ospi_memories", # sub-block: storage parts (flash/HyperRAM); MPNs have no chips/ driver -- excluded like nor_flash/emmc below
147
+ # Storage-class fields encode the SoC controller / peripheral name
148
+ # that reaches the on-module storage (e.g. `nor_flash: xspi` -> the
149
+ # NOR flash is wired to the xSPI controller; `emmc: sd0` -> eMMC on
150
+ # SD/MMC controller 0). They are routing annotations, not chip
151
+ # slugs, and have no `chips/<part>/` driver behind them; emitting
152
+ # them as CHIP_<NAME> trips the Zephyr build with an undefined-symbol
153
+ # warning (no CONFIG_ALP_SDK_CHIP_XSPI / SD0 declaration exists).
154
+ "nor_flash",
155
+ "emmc",
156
+ })
157
+
158
+ # Any `<x>_driver_status` field (nor_flash_driver_status, emmc_driver_status,
159
+ # and whatever the next one is) is a maturity tier -- none/planned/partial/
160
+ # complete -- never a chip slug. A denylist entry per field re-opens this
161
+ # leak every time a new one is added (it did once already: the literal
162
+ # string "none" reached CONFIG_ALP_SDK_CHIP_NONE=y before this suffix check
163
+ # existed). Matched by suffix, not enumerated by name, so it can't miss the
164
+ # next one (alp-sdk #1169).
165
+ _DRIVER_STATUS_SUFFIX = "_driver_status"
166
+
167
+
168
+ def _slugs_from_on_module(on_module: dict) -> list[str]:
169
+ """Extract unique, non-TBD chip slugs from an ``on_module:`` block.
170
+
171
+ Walks every scalar field that is NOT in ``_ON_MODULE_NON_CHIP_FIELDS``,
172
+ then recurses into the ``i2c_devices`` sub-block (extracting the
173
+ ``chip:`` field from each device entry). ``ospi_memories`` and the
174
+ ``hyperram`` block are storage parts (NOR flash / HyperRAM) with no
175
+ ``chips/<part>/`` driver, so their MPNs are NOT extracted as chip
176
+ slugs (emitting them as ``CONFIG_ALP_SDK_CHIP_<X>`` would trip
177
+ Zephyr's undefined-symbol guard). Duplicate slugs and values of
178
+ ``TBD`` / ``null`` are silently dropped.
179
+
180
+ A chip can ALSO be named by a plain top-level scalar field (e.g.
181
+ ``secure_element: optiga_trust_m``) naming which part the design
182
+ carries, distinct from the ``i2c_devices`` entry that records whether
183
+ THIS SKU actually has it fitted. Where both exist for the same chip,
184
+ ``i2c_devices[].assembled`` is the more precise source and wins: a
185
+ device marked ``assembled: false`` (hard DNP, e.g. E1M-AEN801's
186
+ Optiga -- footprint shared with E1M-AEN803, DNP=1 on this batch) or
187
+ ``assembled: optional`` (BOM-variant; the customer opts in via
188
+ `board.populated:`) must not auto-enable as a chip driver EVEN when
189
+ a scalar field also names the same chip (#1980 follow-up -- fixing
190
+ only the `i2c_devices` loop left the scalar-field path still leaking
191
+ `optiga_trust_m` into `_resolve_chip_states`' always-True SoM-intrinsic
192
+ set).
193
+
194
+ Returns a sorted, deduplicated list of slug strings.
195
+ """
196
+ seen: set[str] = set()
197
+ not_auto_enable: set[str] = set()
198
+
199
+ def _add(val: object) -> None:
200
+ if not val or _is_tbd(val):
201
+ return
202
+ if not isinstance(val, str):
203
+ return
204
+ seen.add(val)
205
+
206
+ # 1. Scalar fields — every key whose value is a plain string and
207
+ # is not in the exclusion list (or a `*_driver_status` field).
208
+ for key, val in on_module.items():
209
+ if key in _ON_MODULE_NON_CHIP_FIELDS or key.endswith(_DRIVER_STATUS_SUFFIX):
210
+ continue
211
+ if isinstance(val, str):
212
+ _add(val)
213
+
214
+ # 2. i2c_devices sub-block — each bus entry contains a `devices:`
215
+ # list; extract the `chip:` field from each device.
216
+ # Devices marked `assembled: false` (hard DNP) or `optional`
217
+ # (BOM variant) must NOT be auto-enabled as chip drivers — the
218
+ # customer explicitly enables an optional one via
219
+ # `board.populated:`, and a hard-DNP one never auto-enables at all.
220
+ i2c_buses = on_module.get("i2c_devices")
221
+ if isinstance(i2c_buses, dict):
222
+ for _bus, bus_entry in i2c_buses.items():
223
+ if not isinstance(bus_entry, dict):
224
+ continue
225
+ for dev in bus_entry.get("devices") or []:
226
+ if not isinstance(dev, dict):
227
+ continue
228
+ chip = dev.get("chip")
229
+ assembled = dev.get("assembled", True)
230
+ if assembled is False or assembled == "optional":
231
+ if isinstance(chip, str):
232
+ not_auto_enable.add(chip)
233
+ continue
234
+ _add(chip)
235
+
236
+ seen -= not_auto_enable
237
+ return sorted(seen)
238
+
239
+
240
+ def _slugs_from_helper_firmware(helper_firmware: list) -> list[str]:
241
+ """Extract unique, non-TBD chip slugs from a ``helper_firmware:`` list.
242
+
243
+ Each entry is a dict; we pull the ``chip:`` field. TBD values and
244
+ missing fields are skipped. Returns a sorted, deduplicated list.
245
+ """
246
+ seen: set[str] = set()
247
+ for entry in helper_firmware or []:
248
+ if not isinstance(entry, dict):
249
+ continue
250
+ chip = entry.get("chip")
251
+ if chip and not _is_tbd(chip):
252
+ seen.add(chip)
253
+ return sorted(seen)
254
+
255
+
256
+ # Slugs that map to BLOCK_ Kconfig symbols rather than CHIP_.
257
+ # These live under blocks/ + <alp/blocks/*.h> because they are
258
+ # SDK-level *block* utilities (`alp_button_led_*`, `alp_pdm_mic_*`)
259
+ # rather than third-party-IC chip drivers; see blocks/README.md.
260
+ #
261
+ # Single source of truth -- kconfig.py's emitter, check_example_portability.py
262
+ # and alp_cli/validator.py's ALP-B008 chip-token check all consult this same
263
+ # set rather than each carrying its own copy (a prior state that had drifted
264
+ # into three independent copies). Only the emitter's consumer relocated into
265
+ # `tan`; the two SDK gates keep reading alp-sdk's own copy.
266
+ _BLOCK_SLUGS = frozenset({"button_led", "pdm_mic"})
267
+
268
+
269
+ # Chip name -> Zephyr subsystem CONFIG_* keys the chip driver
270
+ # depends on. Mirrors the `depends on ...` line in each
271
+ # `config ALP_SDK_CHIP_<NAME>` entry in zephyr/Kconfig: enabling
272
+ # a chip driver doesn't auto-select its subsystem, so the loader
273
+ # emits the matching `CONFIG_<SUBSYS>=y` here.
274
+ #
275
+ # RELOCATED from alp-sdk's `scripts/alp_project_emit/__init__.py`, whose only
276
+ # consumer was ever `_emit_chips` in this package's `kconfig.py`.
277
+ #
278
+ # DEBT, stated plainly: this IS a hardware fact and it now lives in `tan`
279
+ # (ADR-0017 / I-26 says facts stay in `metadata/**`). It moved because no
280
+ # metadata file carries it -- a chip manifest's `bus: i2c` cannot distinguish
281
+ # `lsm6dso` -> `("I2C",)` from `tas2563` -> `("I2C", "GPIO")`, so deriving it
282
+ # from existing metadata would change the emitted Kconfig. Retires when a
283
+ # registry (`metadata/registries/chip-subsystems.json`, alongside
284
+ # peripheral-kconfig.json) declares it and this table becomes a loader like
285
+ # `peripheral_kconfig` above.
286
+ _CHIP_SUBSYSTEMS: dict[str, tuple[str, ...]] = {
287
+ # GPIO-only
288
+ "button_led": ("GPIO",),
289
+ "cam_mux_pi3wvr626": ("GPIO",),
290
+ # SPI + GPIO
291
+ "ssd1331": ("SPI", "GPIO"),
292
+ "cc3501e": ("SPI", "GPIO"),
293
+ # I2C + GPIO
294
+ "tas2563": ("I2C", "GPIO"),
295
+ # I2C-only
296
+ "lsm6dso": ("I2C",),
297
+ "ssd1306": ("I2C",),
298
+ "bme280": ("I2C",),
299
+ "lis2dw12": ("I2C",),
300
+ "ov5640": ("I2C",),
301
+ "icm42670": ("I2C",),
302
+ "bmi323": ("I2C",),
303
+ "bmp581": ("I2C",),
304
+ "tmp112": ("I2C",),
305
+ "rv3028c7": ("I2C",),
306
+ "optiga_trust_m": ("I2C",),
307
+ "eeprom_24c128": ("I2C",),
308
+ "tcal9538": ("I2C",),
309
+ "ina228": ("I2C",),
310
+ "ina236": ("I2C",),
311
+ # pdm_mic helper has no subsystem dep declared in Kconfig
312
+ # (uses <alp/i2s.h> when enabled at v0.2+).
313
+ # v0.5 §D.AI batch -- 18 vision / display / accelerator chips.
314
+ "ov2640": ("I2C",),
315
+ "ov5645": ("I2C",),
316
+ "ov7670": ("I2C",),
317
+ "ov9281": ("I2C",),
318
+ "ar0234": ("I2C",),
319
+ "imx219": ("I2C",),
320
+ "imx477": ("I2C",),
321
+ "gc2145": ("I2C",),
322
+ "ti_ds90ub953_954": ("I2C",),
323
+ "maxim_max9295_9296": ("I2C",),
324
+ "st7789": ("SPI", "GPIO"),
325
+ "ili9341": ("SPI", "GPIO"),
326
+ "ili9488": ("SPI", "GPIO"),
327
+ "ra8875": ("SPI",),
328
+ "sh1106": ("I2C",),
329
+ "il3820": ("SPI", "GPIO"),
330
+ "gdew0154t8": ("SPI", "GPIO"),
331
+ "hailo_8l": ("GPIO",),
332
+ # v0.5 §D.industrial batch -- 18 industrial sensing / control chips.
333
+ "bmp390": ("I2C",),
334
+ "ms5611": ("I2C",),
335
+ "lps22hb": ("I2C",),
336
+ "vl53l1x": ("I2C",),
337
+ "vl53l5cx": ("I2C",),
338
+ "a02yyuw": ("SERIAL",),
339
+ "drv8833": ("PWM",),
340
+ "drv8825": ("PWM", "GPIO"),
341
+ "tmc2209": ("SERIAL",),
342
+ "a4988": ("PWM", "GPIO"),
343
+ "as5048a_b": ("I2C",),
344
+ "mt6701": ("I2C",),
345
+ "hx711": ("GPIO",),
346
+ "max31855": ("SPI",),
347
+ "max31865": ("SPI",),
348
+ "tsl2591": ("I2C",),
349
+ "qmc5883l": ("I2C",),
350
+ "veml7700": ("I2C",),
351
+ # v0.5 §D.iot batch -- 9 IoT / connectivity chips.
352
+ "quectel_bg95": ("SERIAL",),
353
+ "quectel_bg77": ("SERIAL",),
354
+ "ublox_sara_r5": ("SERIAL",),
355
+ "semtech_sx1262": ("SPI", "GPIO"),
356
+ "semtech_sx1276": ("SPI", "GPIO"),
357
+ "ublox_neo_m9n": ("SERIAL",),
358
+ "ublox_max_m10s": ("SERIAL",),
359
+ "atgm336h": ("SERIAL",),
360
+ "atecc608b": ("I2C",),
361
+ # v0.5 §D.audio batch -- 6 audio chips.
362
+ "ics_43434": (), # no Zephyr subsystem dep; sample flow via <alp/i2s.h>
363
+ "inmp441": (),
364
+ "wm8960": ("I2C",),
365
+ "tlv320aic3204": ("I2C",),
366
+ "max98357a": ("GPIO",),
367
+ "es8388": ("I2C",),
368
+ # SoM-intrinsic batch (issue #1487) -- act8760/tps628640/
369
+ # da9292/clk_5l35023b are I2C-only PMIC/clock parts; pi3dbs12212/
370
+ # murata_lbee5hy2fy/deepx_dxm1/gd32_swd are GPIO-only. All nine were
371
+ # missing from this table despite each having a `config
372
+ # ALP_SDK_CHIP_<NAME>` / `depends on` entry in
373
+ # zephyr/kconfigs/chips.kconfig, so the loader turned the chip on
374
+ # without turning its dependency on, and Kconfig silently dropped
375
+ # the chip assignment as unmet (issue #1487).
376
+ "act8760": ("I2C",),
377
+ "tps628640": ("I2C",),
378
+ "pi3dbs12212": ("GPIO",),
379
+ "da9292": ("I2C",),
380
+ "clk_5l35023b": ("I2C",),
381
+ "murata_lbee5hy2fy": ("GPIO",),
382
+ "deepx_dxm1": ("GPIO",),
383
+ "gd32_swd": ("GPIO",),
384
+ # gd32g553 declares `depends on (SPI || I2C)` -- an OR, not an AND:
385
+ # the driver's bridge protocol is genuinely hybrid (both transports
386
+ # compiled in, either usable at runtime; see chips/gd32g553/
387
+ # gd32g553.c and docs/gd32-bridge-protocol.md), so there is no
388
+ # single right subsystem to force on. Deliberately over-inclusive
389
+ # here rather than under (issue #1487's own bug class): turning on
390
+ # both is always sufficient for the `||`, whereas picking only one
391
+ # would silently drop the other transport the same way the missing
392
+ # entries above did.
393
+ "gd32g553": ("SPI", "I2C"),
394
+ }