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,202 @@
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ """SoC on-die flash aperture resolution + region classification (alp-sdk#1365 split B).
4
+
5
+ `resolve_aperture()` derives a SoM preset's declared on-die MRAM aperture so
6
+ `carveout.py` and `partition.py` can derive the same `flash` / `ram` /
7
+ `unclassified` / `unresolved` verdict for a `memory_map:` row, instead of
8
+ trusting the legacy `carveout:` flag outright.
9
+
10
+ Depends only downward -- som_metadata (`resolve_soc_path`,
11
+ `_resolve_silicon_variant`), memregion (`_region_size_bytes`), and
12
+ whole_device_alias (`is_whole_device_alias`, alp-sdk#2073); nothing
13
+ calls back into the `tan.planner` package. Upstream keeps that last
14
+ dependency flat and package-free because `gen_zephyr_board.py` sits
15
+ outside the `alp_orchestrate` package; here both callers live inside
16
+ `tan.planner`, so it is an ordinary sibling module -- see its own
17
+ docstring for why it stays a module rather than being inlined into
18
+ each caller.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import json
24
+ from pathlib import Path
25
+ from typing import Any, Optional
26
+
27
+ from .memregion import _region_size_bytes
28
+ from .som_metadata import _resolve_silicon_variant, resolve_soc_path
29
+ from .whole_device_alias import is_whole_device_alias
30
+
31
+ # The four verdicts `classify_region()` can return. Not an enum -- every
32
+ # caller compares against a string literal, matching the rest of this
33
+ # codebase's metadata-classification helpers (e.g. `resolve_memory_map`'s
34
+ # region dicts).
35
+ RegionClass = str # "flash" | "ram" | "unclassified" | "unresolved"
36
+
37
+
38
+ def resolve_aperture(
39
+ preset: dict[str, Any],
40
+ metadata_root: Path,
41
+ ) -> Optional[tuple[int, int]]:
42
+ """Resolve a SoM preset's declared on-die MRAM aperture as `[base, top)`.
43
+
44
+ `base` comes from the preset's SoC's `soc_flash_base`; `top` is
45
+ `base + variants[].mram_mb * 1 MiB` for the VARIANT the preset resolves
46
+ to -- never the SoC's top-level `soc_flash_mb`, because an E3 ships a
47
+ 5.5 MB and a 1.5 MB variant off the same base
48
+ (metadata/socs/alif/ensemble/e3.json). `resolve_soc_path` and
49
+ `_resolve_silicon_variant` (`.som_metadata`) are the single source for
50
+ the SoC-path and variant resolution; this function does not re-derive
51
+ the vendor/family/part split.
52
+
53
+ Returns None -- "no aperture declared, skip every aperture-anchored
54
+ check" -- when the preset names no SoC, the SoC omits `soc_flash_base`,
55
+ or the resolved variant has no usable `mram_mb`. Never guesses.
56
+ """
57
+ soc_path = resolve_soc_path(preset.get("silicon"), metadata_root)
58
+ if soc_path is None or not soc_path.is_file():
59
+ return None
60
+ try:
61
+ soc_spec = json.loads(soc_path.read_text(encoding="utf-8"))
62
+ except (OSError, json.JSONDecodeError):
63
+ return None
64
+ if not isinstance(soc_spec, dict):
65
+ return None
66
+ base = soc_spec.get("soc_flash_base")
67
+ if not isinstance(base, int) or isinstance(base, bool):
68
+ return None
69
+ variant = _resolve_silicon_variant(preset, metadata_root)
70
+ if not isinstance(variant, dict):
71
+ return None
72
+ mram_mb = variant.get("mram_mb")
73
+ if not isinstance(mram_mb, (int, float)) or isinstance(mram_mb, bool):
74
+ return None
75
+ top = base + int(round(mram_mb * 1024 * 1024))
76
+ return base, top
77
+
78
+
79
+ def region_extent(region: dict[str, Any]) -> Optional[tuple[int, int]]:
80
+ """`[base, base + size)` for one `memory_map:` region, or None when the
81
+ base is unresolved (the `"TBD"` string, or absent) or the size can't be
82
+ read. Callers must skip an unresolved extent rather than guessing at it
83
+ -- never fold it into a gap or a class verdict.
84
+ """
85
+ base = region.get("base")
86
+ if not isinstance(base, int) or isinstance(base, bool):
87
+ return None
88
+ size_bytes = _region_size_bytes(region)
89
+ if size_bytes is None:
90
+ return None
91
+ return base, base + size_bytes
92
+
93
+
94
+ def classify_region(
95
+ region: dict[str, Any],
96
+ aperture: Optional[tuple[int, int]],
97
+ is_preset_authored: bool,
98
+ ) -> RegionClass:
99
+ """Classify one `memory_map:` row against the SoC's declared aperture
100
+ (alp-sdk#1365 split B).
101
+
102
+ Four verdicts. Containment is tested BEFORE `is_preset_authored` is
103
+ ever consulted -- a derived row's extent can still prove `"flash"`,
104
+ and skipping straight to `"ram"` for every non-authored row would
105
+ discard that proof in the exact direction this module exists to
106
+ protect (containment is ONE-SIDED: inside proves flash, outside
107
+ proves nothing -- it does not follow that "not proven flash" means
108
+ "safe to call RAM without looking"). Order of evaluation:
109
+
110
+ 1. `"unresolved"` -- the region's own `base` doesn't resolve, OR no
111
+ aperture is declared for this SoC at all (`aperture is None`).
112
+ There is nothing to compare in either case; callers must honour
113
+ an authored flag (`write_authority`, or the legacy `carveout`)
114
+ if one is present rather than guess. This is also what makes
115
+ split B a provable no-op on every non-Alif SoM: with no declared
116
+ aperture, EVERY row on that SoM lands here, so a caller that
117
+ special-cases `aperture is None` before ever calling this
118
+ function reproduces the pre-split-B behaviour byte-for-byte.
119
+
120
+ 2. `"flash"` -- the region's resolved extent is CONTAINED in the
121
+ aperture (including the whole-device alias case, extent ==
122
+ aperture exactly, e.g. `mram_main` once its `base` stops being
123
+ `"TBD"`). Containment is proof regardless of authorship: the
124
+ on-die MRAM aperture holds nothing else, so a DERIVED row that
125
+ happens to sit inside it is flash too, not RAM by default.
126
+
127
+ 3. `"ram"` -- containment did NOT prove flash (the extent lies
128
+ outside the aperture), AND the region was NOT authored by the
129
+ SoM preset itself (a SoC-level `memory_regions` row, or a row
130
+ `resolve_memory_map`'s derivation branch built from the silicon
131
+ variant). RAM by construction, needs no authority -- these rows
132
+ are what keep every V2N/V2M derivation byte-identical.
133
+
134
+ 4. `"unclassified"` -- containment did NOT prove flash, and the
135
+ region WAS authored by the SoM preset. Containment is
136
+ ONE-DIRECTIONAL: outside proves NOTHING -- Ensemble's OSPI XIP
137
+ windows sit outside `[soc_flash_base, ...)` and are still flash,
138
+ and the same OSPI0 controller carries a HyperRAM alongside the
139
+ NOR on a different chip_select. A preset-authored row landing
140
+ here needs `write_authority: customer_runtime` to be IPC-eligible
141
+ (P1); a future authored OSPI XIP row must NOT silently become an
142
+ IPC candidate just because it resolves outside the aperture.
143
+ """
144
+ ext = region_extent(region)
145
+ if ext is None:
146
+ return "unresolved"
147
+ if aperture is None:
148
+ return "unresolved"
149
+ lo, hi = ext
150
+ full_lo, full_hi = aperture
151
+ if is_whole_device_alias(ext, aperture):
152
+ return "flash" # whole-device alias -- the device itself
153
+ if lo >= full_lo and hi <= full_hi:
154
+ return "flash" # strictly contained -- a partition inside the device
155
+ if not is_preset_authored:
156
+ return "ram" # outside the aperture, and not preset-authored
157
+ return "unclassified" # outside the aperture -- proves nothing
158
+
159
+
160
+ def is_partition_inside_aperture(
161
+ region: dict[str, Any],
162
+ aperture: Optional[tuple[int, int]],
163
+ ) -> Optional[bool]:
164
+ """P2: is `region` a partition INSIDE a flash device, not a device of
165
+ its own?
166
+
167
+ True when the region's extent is a PROPER subset of `aperture` (e.g.
168
+ AEN's `mcuboot` / `he_slot0` / `hp_slot0` / `reserved` / `storage` /
169
+ `atoc`, each a fine-grained slice of the on-die MRAM window). False
170
+ ONLY when the extent equals the aperture exactly (the region IS the
171
+ device -- `mram_main`, once resolved) -- that is the one case
172
+ containment proves is a device, not a partition. Everything else
173
+ is None, including when the extent lies OUTSIDE the aperture
174
+ entirely: containment is ONE-SIDED (this module's governing rule) --
175
+ inside proves flash, outside proves NOTHING, so a region outside the
176
+ aperture might legitimately be a device of its own (e.g. an OSPI
177
+ part) or might not; this function cannot tell, and returning a
178
+ definite `False` there would let a caller read "not proven inside" as
179
+ "is a device" when the honest answer is "ask the authored flag
180
+ instead".
181
+
182
+ None also covers the pre-existing case where the extent or the
183
+ aperture itself can't be resolved. In every None case callers must
184
+ fall back to the legacy `carveout:` flag rather than guess, which is
185
+ also what keeps this a no-op wherever the aperture never resolves
186
+ (every non-Alif SoM), the row's own base is still TBD (no shipped AEN
187
+ preset today -- `mram_main` was the standing example until #2053
188
+ resolved it on all seven), or the row resolves a base outside the
189
+ declared aperture.
190
+ """
191
+ if aperture is None:
192
+ return None
193
+ ext = region_extent(region)
194
+ if ext is None:
195
+ return None
196
+ lo, hi = ext
197
+ full_lo, full_hi = aperture
198
+ if is_whole_device_alias(ext, aperture):
199
+ return False # the device itself -- extent equals the aperture exactly
200
+ if lo >= full_lo and hi <= full_hi:
201
+ return True # proper subset -- a partition inside the device
202
+ return None # outside the aperture -- proves nothing either way