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,242 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Renesas DRP-AI compiler adapter (host model compiler).
3
+
4
+ DRP-AI uses the DRP-AI TVM toolchain (github.com/renesas-rz/rzv_drp-ai_tvm),
5
+ powered by the EdgeCortix MERA(TM) compiler. Its high-level driver is the
6
+ ``compile_onnx_model_quant.py`` tutorial script: it takes an ONNX model + a
7
+ calibration image directory and emits a multi-file "Runtime Model Data" object
8
+ DIRECTORY (drp_desc.bin / weight.bin / addr_map.txt / deploy.json / deploy.so /
9
+ preprocess/ ...) that the on-device DRP-AI TVM runtime (MeraDrpRuntimeWrapper)
10
+ loads via ``LoadModel(<dir>)``. The toolchain build also needs the cross
11
+ toolchain root and (for V2N/V2H) the ``PRODUCT`` env set; the tutorial script
12
+ hard-requires ``PRODUCT in {V2H, V2N}``.
13
+
14
+ Because the artifact is a *directory*, the adapter packs it into a single
15
+ deterministic ``.tar`` byte blob with ``blob_format`` ``"drpai_dir"`` (the
16
+ device-side ``_fmt_enum`` maps that to ``ALP_INFERENCE_MODEL_DRPAI``; the
17
+ ``.alpmodel`` loader stages the tar back out to a dir before handing the path
18
+ to the runtime).
19
+
20
+ The toolchain is large and account-/source-gated (the prebuilt MERA2 wheels +
21
+ the DRP-AI Translator), so it is NOT bundled. ``is_available()`` is True only
22
+ when ``ALP_DRPAI_TVM_HOME`` points at a built install; otherwise the drpai
23
+ target is a coverage skip (detect-and-skip), mirroring the DEEPX ``dxcom``
24
+ adapter. The A55 DRP-AI runtime backend is ``src/yocto/inference_drpai.cpp``
25
+ (bench-gated)."""
26
+ from __future__ import annotations
27
+ import io
28
+ import os
29
+ import re
30
+ import subprocess
31
+ import tarfile
32
+ from pathlib import Path
33
+
34
+ from tan.core.subprocess_env import spawn_env
35
+ from . import CompilerAdapter, Blob
36
+
37
+ # The TVM/MERA build runs quantization + DRP-AI translation; minutes for a real
38
+ # model, bounded so CI (when it ever runs) can't hang.
39
+ _DRPAI_TIMEOUT_S = 1800
40
+
41
+ # Files the DRP-AI Translator is contractually required to emit into the object
42
+ # dir (per run_drp_quant_compiler.sh's expected_result_files). We assert at
43
+ # least the core descriptor + weights landed before declaring success.
44
+ _REQUIRED_ARTIFACTS = ("drp_desc.bin", "weight.bin", "addr_map.txt")
45
+
46
+
47
+ def _tvm_home() -> Path | None:
48
+ root = os.environ.get("ALP_DRPAI_TVM_HOME")
49
+ return Path(root) if root and Path(root).is_dir() else None
50
+
51
+
52
+ def _parse_shape_dims(input_shape) -> list[int] | None:
53
+ """Parse input_shape into a list of dimension ints, accepting either
54
+ spelling board.yaml (YAML) can hand us: a comma-separated string
55
+ (``"1,3,224,224"``) or an already-parsed YAML flow-sequence list/tuple
56
+ (``[1, 3, 224, 224]``). Returns None when it parses as neither -- callers
57
+ treat that as "not the 224x224 classifier geometry" rather than
58
+ crashing on a malformed value."""
59
+ if isinstance(input_shape, (list, tuple)):
60
+ try:
61
+ return [int(d) for d in input_shape]
62
+ except (TypeError, ValueError):
63
+ return None
64
+ if not isinstance(input_shape, str):
65
+ return None
66
+ try:
67
+ return [int(d.strip()) for d in input_shape.split(",")]
68
+ except ValueError:
69
+ return None
70
+
71
+
72
+ def _is_224_imagenet_shape(input_shape) -> bool:
73
+ """True when input_shape is the 224x224 ImageNet-classifier geometry the
74
+ vendor tutorial's ``--images`` path hard-codes.
75
+
76
+ ``compile_onnx_model_quant.py`` always runs calibration images through
77
+ ``pre_process_imagenet_pytorch()``, whose body ignores the ``dims``
78
+ argument it accepts and unconditionally does resize(256) +
79
+ center_crop(224) -- so ``--images`` only ever produces correctly-shaped
80
+ calibration tensors for a 3-channel, 224x224 model in NCHW
81
+ (``1,3,224,224``, the layout ONNX -- the only format this adapter accepts,
82
+ see accepts() -- uses by convention). Anything else -- e.g. a detector's
83
+ real geometry like YOLOX's ``1,3,640,640`` -- silently mismatches and the
84
+ vendor tool aborts deep inside with a shape-broadcast error after the
85
+ (multi-minute) compile has already run. See alp-sdk#1271.
86
+
87
+ Compares the PARSED dimensions (via _parse_shape_dims), never a
88
+ stringified spelling: ``str([1, 3, 224, 224])`` is
89
+ ``'[1, 3, 224, 224]'``, and ``.split(",")`` on THAT tears into
90
+ ``'[1'``, ``' 3'``, ``' 224'``, ``' 224]'`` -- none of which parse as
91
+ plain ints -- so a valid YAML-list 224x224 shape was misdiagnosed as
92
+ unsupported when this used to normalize input_shape to str() first
93
+ (alp-sdk#1271 round 4)."""
94
+ return _parse_shape_dims(input_shape) == [1, 3, 224, 224]
95
+
96
+
97
+ def _compiler_version(tvm_home: Path) -> str:
98
+ """Best-effort toolchain version from the DRP-AI TVM checkout.
99
+
100
+ Reads the repo's setup version file when present; falls back to a plain
101
+ 'drp-ai_tvm' tag. Never raises -- version reporting is non-fatal.
102
+
103
+ `UnicodeDecodeError` is caught alongside `OSError` (tan-cli#1116,
104
+ measured escaping before this fix): it is a `ValueError`, not an
105
+ `OSError`, so a non-UTF-8 version file used to raise raw past this
106
+ function's own "Never raises" contract instead of falling through to
107
+ the next candidate the same way a missing or unreadable one already
108
+ does."""
109
+ for rel in ("setup/version", "version", "VERSION"):
110
+ vf = tvm_home / rel
111
+ try:
112
+ txt = vf.read_text(encoding="utf-8").strip()
113
+ except (OSError, UnicodeDecodeError):
114
+ continue
115
+ m = re.search(r"\d+\.\d+(?:\.\d+)?", txt)
116
+ if m:
117
+ return f"drp-ai_tvm {m.group(0)}"
118
+ return "drp-ai_tvm"
119
+
120
+
121
+ def _tar_dir(obj_dir: Path) -> bytes:
122
+ """Pack the object dir into a single deterministic .tar byte blob.
123
+
124
+ Deterministic: sorted entries, zeroed mtime/uid/gid/owner so the same
125
+ inputs reproduce byte-identical blobs (matters for content-addressed
126
+ .alpmodel builds + CI diffing)."""
127
+ buf = io.BytesIO()
128
+ with tarfile.open(fileobj=buf, mode="w") as tar:
129
+ for path in sorted(obj_dir.rglob("*")):
130
+ if not path.is_file():
131
+ continue
132
+ info = tarfile.TarInfo(name=str(path.relative_to(obj_dir)))
133
+ data = path.read_bytes()
134
+ info.size = len(data)
135
+ info.mtime = 0
136
+ info.uid = info.gid = 0
137
+ info.uname = info.gname = ""
138
+ tar.addfile(info, io.BytesIO(data))
139
+ return buf.getvalue()
140
+
141
+
142
+ class DrpaiAdapter(CompilerAdapter):
143
+ backend = "drpai"
144
+ requires_compile_opts = True # needs input shape/name + calib images
145
+
146
+ def is_available(self) -> bool:
147
+ return _tvm_home() is not None
148
+
149
+ def accepts(self, src_format: str) -> bool:
150
+ return src_format == "onnx" # DRP-AI TVM ingests ONNX
151
+
152
+ def compile(self, source: Path, *, accel_config: str, out_dir: Path,
153
+ opts: dict | None = None,
154
+ vela_memory_mode: str | None = None,
155
+ vela_system_config: str | None = None,
156
+ vela_vendor_system_config: str | None = None,
157
+ vela_vendor_config_filename: str | None = None,
158
+ soc_declares_dram: bool | None = None) -> Blob:
159
+ tvm_home = _tvm_home()
160
+ if tvm_home is None:
161
+ raise RuntimeError(
162
+ "DRP-AI compile needs the DRP-AI TVM toolchain; set "
163
+ "ALP_DRPAI_TVM_HOME to a built rzv_drp-ai_tvm install")
164
+
165
+ opts = opts or {}
166
+ # The TVM driver needs the model input geometry + a calibration image
167
+ # set (post-training INT8 quantization); these come from board.yaml
168
+ # models[].compile.drpai. (accel_config is "" for DRP-AI -- targets.py
169
+ # only populates it for Ethos-U; the DRP-AI product comes from the
170
+ # models[].compile.drpai config, not accel_config.)
171
+ input_shape = opts.get("input_shape")
172
+ input_name = opts.get("input_name")
173
+ images = opts.get("images")
174
+ if not input_shape or not input_name or not images:
175
+ raise RuntimeError(
176
+ "DRP-AI compile needs models[].compile.drpai with "
177
+ "input_shape, input_name and images (a calibration image dir)")
178
+
179
+ # The vendor tutorial's --images path only preprocesses to 224x224
180
+ # (see _is_224_imagenet_shape). Fail here, before the multi-minute
181
+ # compile runs, instead of forwarding a detector/segmentation
182
+ # geometry into a `could not broadcast` crash deep in vendor code.
183
+ # board.yaml (YAML) can hand us input_shape as either a comma string
184
+ # ("1,3,224,224") or an already-parsed flow-sequence list
185
+ # ([1, 3, 224, 224]); _is_224_imagenet_shape/_parse_shape_dims compare
186
+ # the PARSED dimensions for both spellings, never a stringified form
187
+ # -- str([1, 3, 224, 224]) is '[1, 3, 224, 224]', which .split(",")
188
+ # tears into tokens ('[1', ' 224]', ...) that don't parse as ints,
189
+ # misdiagnosing a valid 224x224 list shape as unsupported.
190
+ if not _is_224_imagenet_shape(input_shape):
191
+ raise RuntimeError(
192
+ f"DRP-AI --images calibration only works for the 224x224 "
193
+ f"ImageNet classifier geometry the vendor tutorial hard-codes "
194
+ f"in pre_process_imagenet_pytorch() (resize-256 + "
195
+ f"center-crop-224); got input_shape={input_shape!r}. A "
196
+ f"detector/segmentation model at this geometry cannot be "
197
+ f"calibrated against real images through this path yet "
198
+ f"(tracked in alp-sdk#1271) -- there is no random-frame "
199
+ f"fallback wired into this adapter today, so this compile "
200
+ f"cannot proceed with calibrated accuracy.")
201
+ # Vendor CLI's -s wants a comma-joined string ("1,3,224,224") --
202
+ # never Python's str() of a list -- so build it from the parsed
203
+ # dims, not from whatever spelling opts.input_shape arrived in.
204
+ shape_arg = ",".join(str(d) for d in _parse_shape_dims(input_shape))
205
+
206
+ product = (opts.get("product") or accel_config or "V2N").upper()
207
+ if product not in ("V2N", "V2H"):
208
+ raise RuntimeError(
209
+ f"DRP-AI compile: unsupported product {product!r} "
210
+ "(expected V2N or V2H)")
211
+
212
+ obj_dir = out_dir / f"{source.stem}_drpai"
213
+ obj_dir.mkdir(parents=True, exist_ok=True)
214
+
215
+ # The tutorial driver lives in the toolchain checkout; invoke it with
216
+ # the model, the output object dir, the input geometry and the
217
+ # calibration images. PRODUCT is consumed from the environment.
218
+ script = tvm_home / "tutorials" / "compile_onnx_model_quant.py"
219
+ cmd = [
220
+ "python3", str(script), str(source),
221
+ "-o", str(obj_dir),
222
+ "-s", shape_arg,
223
+ "-i", str(input_name),
224
+ "--images", str(images),
225
+ ]
226
+ env = spawn_env({"PRODUCT": product})
227
+ try:
228
+ proc = subprocess.run(cmd, capture_output=True, text=True,
229
+ timeout=_DRPAI_TIMEOUT_S, env=env)
230
+ except subprocess.TimeoutExpired as exc:
231
+ raise RuntimeError(f"DRP-AI compile timed out after {exc.timeout}s") from exc
232
+ if proc.returncode != 0:
233
+ raise RuntimeError(
234
+ f"DRP-AI compile failed: {proc.stderr.strip() or proc.stdout.strip()}")
235
+
236
+ missing = [f for f in _REQUIRED_ARTIFACTS if not (obj_dir / f).is_file()]
237
+ if missing:
238
+ raise RuntimeError(
239
+ f"DRP-AI compile produced no {', '.join(missing)} in {obj_dir}")
240
+
241
+ return Blob(format="drpai_dir", payload=_tar_dir(obj_dir),
242
+ compiler_version=_compiler_version(tvm_home))