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
@@ -0,0 +1,237 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """`diagnostics.link:` -- the image link target (tan-cli#1350, ADR-0026).
3
+
4
+ `link: itcm` turns a board.yaml into an AEN Flow C image: linked into the
5
+ M55-HE ITCM (base 0x0, global window 0x58000000) for `tan flash --ram`, which
6
+ loads the ELF there and reads `ram_console_buf`. Without it the only route
7
+ was hand-copying alp-sdk's `scripts/bench/aen/aen-flowc-itcm.{conf,overlay}`
8
+ into the app.
9
+
10
+ The planner owns the retarget (ADR-0026): it renders the same two halves the
11
+ bench pair carries -- the Kconfig half and the devicetree half, BOTH required
12
+ (the conf alone still links into MRAM, the overlay alone leaves
13
+ `CONFIG_FLASH_LOAD_OFFSET` at the slot0 offset) -- as two extra per-slice
14
+ config artefacts layered AFTER the slice's `alp.conf`.
15
+
16
+ Pure: no IO, no SDK read. HE-only by design: the knob retargets the M55-HE
17
+ slice only, and is refused when the project has no M55-HE app of its own (an
18
+ M55-HP-only project included), on any SKU but AEN801/AEN803, with a sysbuild
19
+ (`boot:`) project, and with an explicit `linux`/`none` console.
20
+
21
+ `console: uart` is accepted (tan-cli#1374). The #1374 bench (e1m-aen-evk-02,
22
+ AEN803, 2026-10-07) ran a UART5 shell RAM-run with ONLY `zephyr,flash = &itcm;`,
23
+ the code-partition delete, `CONFIG_USE_DT_CODE_PARTITION=n` and
24
+ `CONFIG_FLASH_LOAD_OFFSET=0x0` hand-added -- no `CONFIG_DCACHE=n`, so the
25
+ D-cache stayed at its board default. A `uart` image therefore gets exactly
26
+ that retarget. The D-cache hang recorded by #1350 concerns the RAM-console
27
+ path, which still gets `CONFIG_DCACHE=n` and the 16 KiB buffer (`ram`/`auto`).
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ from typing import Any
33
+
34
+ from .models import BoardProject, OrchestratorError, Slice
35
+ from .secure import emit_sysbuild_conf, emit_tfm_sysbuild_conf
36
+
37
+ UNSUPPORTED_CODE = "build.link-itcm-unsupported"
38
+ CONSOLE_CONFLICT_CODE = "build.link-itcm-console-conflict"
39
+
40
+ #: Build-dir file names of the two extra artefacts (siblings of `alp.conf`).
41
+ CONF_NAME = "alp-link-itcm.conf"
42
+ OVERLAY_NAME = "alp-link-itcm.overlay"
43
+
44
+ _HE_CORE_ID = "m55_he"
45
+ #: The SKUs the Flow C ITCM retarget is proven on (E8: AEN801 / AEN803, bench
46
+ #: 2026-07..10). Other Alif Ensemble SKUs have different ITCM maps / SoC
47
+ #: variants and are refused until someone proves them.
48
+ _PROVEN_SKUS = ("E1M-AEN801", "E1M-AEN803")
49
+ #: The schema enum already rejects anything else; the checks below that read
50
+ #: the value defensively exist for hand-built projects that skip the schema.
51
+ _LINK_VALUES = ("auto", "itcm")
52
+ #: `diagnostics.console:` values a Flow C image accepts: the RAM console (the
53
+ #: default; read over SWD) or the board UART (a RAM-run shell, tan-cli#1374).
54
+ #: `alp` is kconfig's own alias of `uart` (`kconfig._CONSOLE_ALIASES`), so it is
55
+ #: the UART console here too and emits exactly the `uart` bytes (tan-cli#1419).
56
+ _CONSOLE_VALUES = ("auto", "ram", "uart", "alp")
57
+
58
+
59
+ class LinkTargetError(OrchestratorError):
60
+ """A `diagnostics.link:` refusal carrying its tan issue code."""
61
+
62
+ def __init__(self, code: str, message: str) -> None:
63
+ super().__init__(message)
64
+ self.code = code
65
+
66
+
67
+ def _console(diagnostics: dict[str, Any] | None) -> str:
68
+ return str((diagnostics or {}).get("console") or "auto").strip().lower()
69
+
70
+
71
+ def uses_ram_console(diagnostics: dict[str, Any] | None) -> bool:
72
+ """Whether an ITCM image uses the RAM console (`auto` is promoted to it):
73
+ True for `auto`/`ram`, False for `uart`, its alias `alp`, and anything else."""
74
+ return _console(diagnostics) in ("auto", "ram")
75
+
76
+
77
+ def link_target(diagnostics: dict[str, Any] | None) -> str:
78
+ """The `diagnostics.link:` value (`auto` when unset). The `.strip().lower()`
79
+ is defensive only: the schema enum is lowercase, exact."""
80
+ raw = (diagnostics or {}).get("link")
81
+ return "auto" if raw is None else str(raw).strip().lower()
82
+
83
+
84
+ def is_itcm_link(diagnostics: dict[str, Any] | None) -> bool:
85
+ return link_target(diagnostics) == "itcm"
86
+
87
+
88
+ def applies_to(diagnostics: dict[str, Any] | None, slice_: Slice) -> bool:
89
+ """Whether `link: itcm` retargets THIS slice: the Zephyr M55-HE only.
90
+
91
+ The knob is project-wide in board.yaml, but a Flow C image is one core's
92
+ ITCM image: the other slices of the project (the AEN stock M55-HP shim,
93
+ the A32 Linux image) build exactly as without it.
94
+ """
95
+ return (is_itcm_link(diagnostics) and slice_.os == "zephyr"
96
+ and slice_.core_id == _HE_CORE_ID)
97
+
98
+
99
+ def check_link_target(project: BoardProject) -> None:
100
+ """Refuse `link: itcm` anywhere but an AEN project with an M55-HE app.
101
+
102
+ Raises `LinkTargetError`; returns None for `auto`/unset.
103
+ """
104
+ target = link_target(project.diagnostics)
105
+ if target == "auto":
106
+ return
107
+ if target not in _LINK_VALUES:
108
+ raise LinkTargetError(
109
+ UNSUPPORTED_CODE,
110
+ f"diagnostics.link: '{target}' is not one of "
111
+ f"{', '.join(_LINK_VALUES)}.")
112
+ if project.sku not in _PROVEN_SKUS:
113
+ raise LinkTargetError(
114
+ UNSUPPORTED_CODE,
115
+ f"diagnostics.link: itcm is proven on the Alif Ensemble E8 "
116
+ f"M55-HE ({', '.join(_PROVEN_SKUS)}); {project.sku} is not "
117
+ f"supported. Remove `diagnostics.link:` for this SoM.")
118
+ declared = (project.raw.get("cores") or {}) if isinstance(
119
+ project.raw, dict) else {}
120
+ he_decl = declared.get(_HE_CORE_ID)
121
+ he = project.cores.get(_HE_CORE_ID)
122
+ if (not isinstance(he_decl, dict) or not he_decl.get("app")
123
+ or he is None or he.os != "zephyr"):
124
+ others = sorted(
125
+ c for c, d in declared.items()
126
+ if c != _HE_CORE_ID and isinstance(d, dict) and d.get("app"))
127
+ hint = (f" The project's own app is on {', '.join(others)}; the "
128
+ f"M55-HP has a separate ITCM window (0x50000000) and is not "
129
+ f"supported -- move the app to `cores.{_HE_CORE_ID}`."
130
+ if others else "")
131
+ raise LinkTargetError(
132
+ UNSUPPORTED_CODE,
133
+ f"diagnostics.link: itcm links the M55-HE ITCM image, but "
134
+ f"`cores.{_HE_CORE_ID}` has no `os: zephyr` app of its own."
135
+ f"{hint}")
136
+ if emit_sysbuild_conf(project) or emit_tfm_sysbuild_conf(project):
137
+ raise LinkTargetError(
138
+ UNSUPPORTED_CODE,
139
+ "diagnostics.link: itcm cannot be combined with a sysbuild "
140
+ "project (`boot:` / `ota:` / TF-M) -- a RAM-run image has no "
141
+ "MCUboot slot.")
142
+ console = _console(project.diagnostics)
143
+ if console not in _CONSOLE_VALUES:
144
+ raise LinkTargetError(
145
+ CONSOLE_CONFLICT_CODE,
146
+ f"diagnostics.link: itcm supports the RAM console or the board "
147
+ f"UART, but diagnostics.console is '{console}'. Use "
148
+ f"`console: ram` (or leave it `auto`) to read the RAM console "
149
+ f"buffer, or `console: uart` for a RAM-run UART shell.")
150
+
151
+
152
+ def apply_link_target(project: BoardProject) -> None:
153
+ """`check_link_target`, then mark the retargeted slice (`Slice.link_target`)
154
+ so the manifest/flash recipe can refuse an MRAM write of it."""
155
+ check_link_target(project)
156
+ for sl in project.cores.values():
157
+ if applies_to(project.diagnostics, sl):
158
+ sl.link_target = "itcm"
159
+
160
+
161
+ #: Floor for the Flow C RAM-console buffer (bytes).
162
+ ITCM_RAM_CONSOLE_MIN_SIZE = 16384
163
+
164
+
165
+ def itcm_conf(ram_console: bool = True, *, app_ram_console_size: int = 0) -> str:
166
+ """Kconfig half of the retarget (+ the bench-proven RAM-run settings).
167
+
168
+ The retarget lines are always emitted. The bench-proven RAM-console
169
+ settings (`CONFIG_DCACHE=n`, the buffer size) only when `ram_console`
170
+ (`console: ram`/`auto`); a `console: uart` image leaves both as the board
171
+ defaults them.
172
+
173
+ `app_ram_console_size` is the `CONFIG_RAM_CONSOLE_BUFFER_SIZE` the app's own
174
+ `prj.conf` sets (0 when none): this conf is layered AFTER it, so a bare
175
+ 16384 would shrink a larger app-set buffer and wrap its console
176
+ (tan-cli#1401). The size is max(16384, app value).
177
+ """
178
+ size = max(ITCM_RAM_CONSOLE_MIN_SIZE, app_ram_console_size)
179
+ retarget = (
180
+ "# Flow C (AEN M55-HE ITCM RAM-run) link retarget -- board.yaml\n"
181
+ "# `diagnostics.link: itcm`. NOT for an image you will flash to MRAM:\n"
182
+ "# it links at 0x0. Kconfig half; the devicetree half is\n"
183
+ f"# {OVERLAY_NAME} -- BOTH are required.\n"
184
+ "#\n"
185
+ "# Stop deriving the link offset from the DT code-partition and force\n"
186
+ "# the ITCM base (undoes the AEN board defconfig's slot0 default and a\n"
187
+ "# literal CONFIG_FLASH_LOAD_OFFSET an app may hard-code).\n"
188
+ "CONFIG_USE_DT_CODE_PARTITION=n\n"
189
+ "CONFIG_FLASH_LOAD_OFFSET=0x0\n"
190
+ )
191
+ if not ram_console:
192
+ return retarget
193
+ return retarget + (
194
+ "# The E8 D-cache maintenance loop hangs on this silicon.\n"
195
+ "CONFIG_DCACHE=n\n"
196
+ "# ram_console_out() WRAPS: a buffer smaller than the app's output\n"
197
+ "# reads back as two interleaved points in the run.\n"
198
+ f"CONFIG_RAM_CONSOLE_BUFFER_SIZE={size}\n"
199
+ )
200
+
201
+
202
+ def itcm_overlay() -> str:
203
+ """Devicetree half: retarget the ROM region to ITCM."""
204
+ return (
205
+ "/*\n"
206
+ " * Flow C (AEN M55-HE ITCM RAM-run) devicetree retarget -- board.yaml\n"
207
+ " * `diagnostics.link: itcm`. Moves zephyr,flash to the ITCM and drops\n"
208
+ " * the code-partition so the image links at 0x0. Kconfig half:\n"
209
+ f" * {CONF_NAME} -- BOTH are required. NOT for an MRAM-flashed image.\n"
210
+ " */\n"
211
+ "\n"
212
+ "/ {\n"
213
+ "\tchosen {\n"
214
+ "\t\t/* path-ref form: the pointer form makes FLASH_SIZE=0 and\n"
215
+ "\t\t * overflows the link */\n"
216
+ "\t\tzephyr,flash = &itcm;\n"
217
+ "\t\t/delete-property/ zephyr,code-partition;\n"
218
+ "\t};\n"
219
+ "};\n"
220
+ )
221
+
222
+
223
+ def extra_config_artefacts(project: BoardProject,
224
+ slice_: Slice) -> list[tuple[str, str]]:
225
+ """`(name, contents)` of the extra per-slice artefacts, in layer order.
226
+
227
+ Empty unless `link: itcm` and this is the Zephyr M55-HE slice.
228
+ """
229
+ if not applies_to(project.diagnostics, slice_):
230
+ return []
231
+ # Lazy: kconfig imports this module (the shared reader of the app's prj.conf).
232
+ from .kconfig import _app_ram_console_size # noqa: PLC0415
233
+
234
+ ram_console = uses_ram_console(project.diagnostics)
235
+ app_size = _app_ram_console_size(project, slice_) if ram_console else 0
236
+ return [(CONF_NAME, itcm_conf(ram_console, app_ram_console_size=app_size)),
237
+ (OVERLAY_NAME, itcm_overlay())]
@@ -0,0 +1,216 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Linux devicetree fragment for per-product core ownership (RZ/V2N family).
3
+
4
+ ONE renderer for two callers: `scripts/gen_linux_ownership_dt.py` (the
5
+ committed SoM-default fragment) and `--emit linux-ownership-dts` (the
6
+ per-project fragment from the project's resolved `ownership:`). Inputs are
7
+ read, never restated: the family core-ownership.yaml, its
8
+ supervisor-links.yaml and the SoC JSON `linux_dt` block (`project.soc_spec`).
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import re
14
+ from pathlib import Path
15
+ from typing import Optional
16
+
17
+ import yaml
18
+
19
+ from .models import OrchestratorError
20
+ from .ownership import instance_pfc, load_ownership_doc, ownership_doc_rel, resolve_ownership
21
+
22
+ # The V2N SoM-default source; a project passes its own family's via render(src=).
23
+ SRC = "metadata/e1m_modules/v2n/core-ownership.yaml"
24
+
25
+
26
+ class GenError(OrchestratorError):
27
+ pass
28
+
29
+
30
+ def load_supervisor_links(metadata_root: Path, family_dir: Optional[str]) -> dict:
31
+ """The family's enabled/disabled supervisor links (V2M shares V2N's)."""
32
+ for fam in (family_dir, "v2n" if (family_dir or "").startswith("v2n") else None):
33
+ if fam:
34
+ p = metadata_root / "e1m_modules" / fam / "supervisor-links.yaml"
35
+ if p.is_file():
36
+ return yaml.safe_load(p.read_text(encoding="utf-8"))["supervisor_links"]
37
+ return {}
38
+
39
+
40
+ def emit_linux_ownership_dts(project) -> str:
41
+ """The Linux ownership fragment for this project's resolved ownership,
42
+ or a comment-only stub when the SoM family has no `assignable:` block."""
43
+ from .loader import _sku_family_dir
44
+ root, fam = project.effective_metadata_root(), _sku_family_dir(project.sku)
45
+ doc = load_ownership_doc(root, fam)
46
+ if not doc or not doc.get("assignable"):
47
+ return "/* No assignable core ownership for this SoM family; nothing to emit. */\n"
48
+ return render(doc, project.soc_spec, load_supervisor_links(root, fam), project.ownership,
49
+ src=ownership_doc_rel(root, fam))[0]
50
+
51
+
52
+ def cm33_clocks(doc: dict, soc: dict, links: dict, own: dict[str, str]) -> list[str]:
53
+ """CPG clock names to keep on for the CM33: enabled supervisor links +
54
+ CM33-owned assignable instances (a hw_blocked instance is never enabled)."""
55
+ linux_dt = soc.get("linux_dt") or {}
56
+ by_label = {v["label"]: v for v in linux_dt.values() if v.get("cpg_clocks")}
57
+ clocks: list[str] = []
58
+
59
+ def add(names: list[str]) -> None:
60
+ clocks.extend(n for n in names if n not in clocks)
61
+
62
+ for name, link in sorted(links.items()):
63
+ if link.get("status") != "enabled":
64
+ continue
65
+ ent = by_label.get(link["dt_label"])
66
+ if ent is None:
67
+ raise GenError(f"supervisor link {name}: no cpg_clocks for &{link['dt_label']} in "
68
+ f"soc linux_dt")
69
+ add(ent["cpg_clocks"])
70
+ for inst, e in sorted(doc["assignable"].items()):
71
+ if own[inst] == "m33" and not e.get("hw_blocked"):
72
+ ent = linux_dt.get(e.get("soc_instance")) or {}
73
+ if not ent.get("cpg_clocks"):
74
+ raise GenError(f"assignable.{inst}: owned by m33 but linux_dt.{e.get('soc_instance')} "
75
+ "has no cpg_clocks")
76
+ add(ent["cpg_clocks"])
77
+ return clocks
78
+
79
+
80
+ def _can_channels(doc: dict, soc: dict, own: dict[str, str]) -> tuple[dict[int, int], set[int], str]:
81
+ """({E1M CAN bus id: SoC channel} for every a55-owned, non-hw_blocked bus,
82
+ {bus ids Linux ENABLES (`linux_enable`)}, shared controller label)."""
83
+ linux_dt = soc.get("linux_dt") or {}
84
+ cans: dict[int, int] = {}
85
+ enabled: set[int] = set()
86
+ label = ""
87
+ for inst, e in doc["assignable"].items():
88
+ m = re.fullmatch(r"e1m_can(\d+)", inst)
89
+ ld = linux_dt.get(e.get("soc_instance")) or {}
90
+ if m and ld.get("channel") is not None and own[inst] == "a55" and not e.get("hw_blocked"):
91
+ bus = int(m.group(1))
92
+ cans[bus], label = ld["channel"], ld["label"]
93
+ # `render` only sets the node okay when linux_enable AND every pad has
94
+ # a PFC code (a GAP leaves the node at the vendor status).
95
+ if e.get("linux_enable") and all(p is not None for _, p in instance_pfc(soc, e)):
96
+ enabled.add(bus)
97
+ return cans, enabled, label
98
+
99
+
100
+ def can_netdev_map(doc: dict, soc: dict, own: dict[str, str]) -> list[str]:
101
+ """Linux netdev per E1M CAN bus id (index = N of `e1m_canN`), "" = none.
102
+
103
+ rcar_canfd names netdevs `can0..` in probe order of the ENABLED channels
104
+ (ascending channel), and exposes no channel id at runtime (#2352), so the
105
+ name is the rank of the instance's SoC channel among the channels Linux
106
+ enables -- i.e. the `linux_enable` ones, the only nodes `render` sets to
107
+ "okay" (same rule as every other peripheral here). `render` forces every
108
+ OTHER channel node disabled, so rank == enabled order by construction.
109
+ Buses that are not enabled map to "": alp_can_open fails closed."""
110
+ cans, enabled, _ = _can_channels(doc, soc, own)
111
+ if not cans:
112
+ return []
113
+ ranked = sorted(cans[b] for b in enabled)
114
+ return [f"can{ranked.index(cans[b])}" if b in enabled else "" for b in range(max(cans) + 1)]
115
+
116
+
117
+ def _group(inst: str) -> tuple[str, str]:
118
+ return f"{inst}_pins", inst.replace("_", "-")
119
+
120
+
121
+ def render(doc: dict, soc: dict, links: dict,
122
+ ownership: Optional[dict[str, str]] = None,
123
+ src: str = SRC) -> tuple[str, set[str]]:
124
+ """(dtsi text, node labels it references). `src` = the family's
125
+ core-ownership.yaml path, quoted in the output."""
126
+ own = ownership or resolve_ownership(doc)
127
+ linux_dt = soc.get("linux_dt") or {}
128
+ pins: list[str] = []
129
+ nodes: list[str] = []
130
+ labels: set[str] = set()
131
+ for inst, e in sorted(doc["assignable"].items()):
132
+ ld = linux_dt.get(e.get("soc_instance"))
133
+ if ld is None:
134
+ raise GenError(f"assignable.{inst}: soc_instance {e.get('soc_instance')!r} "
135
+ f"is not a key of soc linux_dt")
136
+ label = ld["label"]
137
+ head = f"/* {inst} ({e['soc_instance']}, &{label}): "
138
+ if e.get("hw_blocked"):
139
+ nodes.append(f"{head}left disabled -- hardware-blocked on every core:\n"
140
+ f" * {e['hw_blocked']['reason']} */")
141
+ continue
142
+ if own[inst] != "a55":
143
+ labels.add(label)
144
+ nodes.append(f"{head}owned by {own[inst]}; Linux must not claim it. */\n"
145
+ f"&{label} {{\n\tstatus = \"disabled\";\n}};")
146
+ continue
147
+ if e.get("linux_enable") and not e.get("linux_evidence"):
148
+ raise GenError(f"assignable.{inst}: linux_enable needs linux_evidence")
149
+ if not e.get("linux_enable"):
150
+ nodes.append(f"{head}owned by a55; left at the vendor status (no `linux_enable` in\n"
151
+ f" * {src} -- Linux enablement is not bench-evidenced). */")
152
+ continue
153
+ rows = instance_pfc(soc, e)
154
+ gaps = [r["peripheral"] for r, p in rows if p is None]
155
+ if gaps:
156
+ nodes.append(f"{head}GAP -- no PFC function code in the SoC JSON\n"
157
+ f" * linux_dt.{e['soc_instance']}.pinmux for {gaps}; node left as the vendor\n"
158
+ " * dtsi has it (disabled). Not guessed. */")
159
+ continue
160
+ grp_label, grp_node = _group(inst)
161
+ body = "".join(
162
+ ("\t\tpinmux = " if i == 0 else "\t\t\t ")
163
+ + f"<RZV2N_PORT_PINMUX({port[-1]}, {pin}, {func})>{';' if i == len(rows) - 1 else ','}"
164
+ f" /* {r['pad']} = {r['peripheral']} */\n"
165
+ for i, (r, (port, pin, func)) in enumerate(rows))
166
+ pins.append(f"\t{grp_label}: {grp_node} {{\n{body}\t}};\n")
167
+ labels.add(label)
168
+ chan = ld.get("channel")
169
+ node = (f"{head}owned by a55. */\n&{label} {{\n"
170
+ f"\tpinctrl-0 = <&{grp_label}>;\n\tpinctrl-names = \"default\";\n"
171
+ f"\tstatus = \"okay\";\n")
172
+ if chan is not None:
173
+ node += f"\n\tchannel{chan} {{\n\t\tstatus = \"okay\";\n\t}};\n"
174
+ labels.add(f"{label}/channel{chan}")
175
+ nodes.append(node + "};")
176
+ out = (
177
+ "/*\n"
178
+ " * GENERATED (scripts/gen_linux_ownership_dt.py, or `--emit linux-ownership-dts`\n"
179
+ f" * for a project) from {src}\n"
180
+ " * and the SoC JSON linux_dt block -- DO NOT EDIT BY HAND.\n"
181
+ " *\n"
182
+ " * Per-product core ownership on the A55 side: each assignable resource\n"
183
+ " * the SoM default gives to Linux is enabled here with pinctrl built from\n"
184
+ " * the metadata; resources owned by the Cortex-M33 or hardware-blocked\n"
185
+ " * are explicitly disabled. Regenerate after editing either source.\n"
186
+ " */\n\n")
187
+ if pins:
188
+ out += "&pinctrl {\n" + "\n".join(pins) + "};\n\n"
189
+ out += "\n\n".join(nodes) + "\n"
190
+ names = ", ".join(f'"{c}"' for c in cm33_clocks(doc, soc, links, own))
191
+ out += ("\n/*\n * Module clocks the Cortex-M33 uses (enabled supervisor links + CM33-owned\n"
192
+ " * assignable instances): the CPG driver keeps them, and their bus-stop gates,\n"
193
+ " * on through clk_disable_unused (0001-clk-renesas-rzv2h-cpg-cm33-owned-clocks).\n"
194
+ " */\n"
195
+ f"&cpg {{\n\trenesas,cm33-owned-clocks = {names};\n}};\n")
196
+ labels.add("cpg")
197
+ nd = can_netdev_map(doc, soc, own)
198
+ if nd:
199
+ cans, enabled, clabel = _can_channels(doc, soc, own)
200
+ on = {cans[b] for b in enabled}
201
+ off = [c for c in range(int((soc.get("peripherals") or {}).get("can_fd", 0)))
202
+ if c not in on]
203
+ if off:
204
+ body = "\n".join(f'\tchannel{c} {{\n\t\tstatus = "disabled";\n\t}};\n' for c in off)
205
+ out += ("\n/*\n * Every CAN-FD channel Linux does not enable is disabled explicitly: rcar_canfd\n"
206
+ " * numbers netdevs by probe order of the ENABLED channels, so the netdev map\n"
207
+ " * below holds only if no other channel is enabled; an empty entry =\n"
208
+ " * no netdev for that bus (#2352).\n */\n"
209
+ f"&{clabel} {{\n{body}}};\n")
210
+ labels.update(f"{clabel}/channel{c}" for c in off)
211
+ names = ", ".join(f'"{n}"' for n in nd)
212
+ out += ("\n/*\n * Linux netdev per E1M CAN bus id (index = N of E1M_X_CANN): rcar_canfd numbers\n"
213
+ " * netdevs by probe order, not by channel, so the SDK's SocketCAN backend reads\n"
214
+ " * this instead of assuming can<N> (#2352).\n */\n"
215
+ f"/ {{\n\talp,e1m-can-netdev = {names};\n}};\n")
216
+ return out, labels