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.
- tan/__init__.py +0 -0
- tan/__main__.py +120 -0
- tan/cli.py +939 -0
- tan/command_table.py +265 -0
- tan/commands/__init__.py +8 -0
- tan/commands/bootstrap_cmd.py +4856 -0
- tan/commands/bootstrap_patches.py +164 -0
- tan/commands/bootstrap_toolchain_fetch.py +155 -0
- tan/commands/bootstrap_toolchain_pin.py +36 -0
- tan/commands/build/__init__.py +1 -0
- tan/commands/build/configure_inputs.py +277 -0
- tan/commands/build/execute.py +1852 -0
- tan/commands/build/host_python.py +59 -0
- tan/commands/build/link_stale.py +78 -0
- tan/commands/build/manifest.py +428 -0
- tan/commands/build/materialise.py +81 -0
- tan/commands/build/token_substitution.py +381 -0
- tan/commands/build/toolchain.py +482 -0
- tan/commands/build/user_defines_wipe.py +115 -0
- tan/commands/build/workspace_patches.py +65 -0
- tan/commands/build_cmd.py +2236 -0
- tan/commands/build_output.py +331 -0
- tan/commands/clean_cmd.py +1183 -0
- tan/commands/completion_cmd.py +786 -0
- tan/commands/debug_config_cmd.py +2425 -0
- tan/commands/diff_cmd.py +940 -0
- tan/commands/doctor_cmd.py +4767 -0
- tan/commands/examples_cmd.py +644 -0
- tan/commands/explain_cmd.py +1319 -0
- tan/commands/faultdecode_cmd.py +931 -0
- tan/commands/flash_atoc_guard.py +240 -0
- tan/commands/flash_cmd.py +5731 -0
- tan/commands/flash_mram_guard.py +150 -0
- tan/commands/flash_ram.py +578 -0
- tan/commands/flash_raw.py +583 -0
- tan/commands/generate_cmd.py +1456 -0
- tan/commands/image_cmd.py +753 -0
- tan/commands/init_cmd.py +1740 -0
- tan/commands/inspect_cmd.py +377 -0
- tan/commands/kconfig_cmd.py +734 -0
- tan/commands/model_cmd.py +1514 -0
- tan/commands/model_device_cmd.py +351 -0
- tan/commands/model_device_live.py +234 -0
- tan/commands/model_host_cmd.py +430 -0
- tan/commands/model_zoo_cmd.py +363 -0
- tan/commands/monitor_actions.py +125 -0
- tan/commands/monitor_cmd.py +626 -0
- tan/commands/monitor_session.py +505 -0
- tan/commands/new_som_cmd.py +1522 -0
- tan/commands/pinmux_cmd.py +568 -0
- tan/commands/presets_cmd.py +1123 -0
- tan/commands/probe_cmd.py +421 -0
- tan/commands/reset_cmd.py +354 -0
- tan/commands/reset_confirm.py +168 -0
- tan/commands/run_cmd.py +637 -0
- tan/commands/scaffold_cmd.py +490 -0
- tan/commands/sdk_cmd.py +1723 -0
- tan/commands/size_cmd.py +1020 -0
- tan/commands/support_bundle_cmd.py +1073 -0
- tan/commands/trace_cmd.py +341 -0
- tan/commands/validate_cmd.py +2009 -0
- tan/commands/west_forward_cmd.py +736 -0
- tan/commands/workspace_patch_check.py +296 -0
- tan/core/__init__.py +1 -0
- tan/core/alp_conf_pregen.py +100 -0
- tan/core/artifact_provenance.py +240 -0
- tan/core/atoc_guard.py +276 -0
- tan/core/atoc_guard_messages.py +232 -0
- tan/core/atoc_replacement.py +118 -0
- tan/core/atomic_write.py +178 -0
- tan/core/board_context.py +351 -0
- tan/core/board_diagnostic.py +111 -0
- tan/core/board_files.py +221 -0
- tan/core/board_validator.py +542 -0
- tan/core/board_validator_compat.py +196 -0
- tan/core/board_validator_run.py +129 -0
- tan/core/board_validator_schema.py +186 -0
- tan/core/board_validator_skew.py +46 -0
- tan/core/board_yaml_edit.py +295 -0
- tan/core/board_yaml_pos.py +118 -0
- tan/core/bootstrap.py +2572 -0
- tan/core/build_plan.py +625 -0
- tan/core/consent.py +104 -0
- tan/core/console_filter.py +245 -0
- tan/core/debug_launch.py +1803 -0
- tan/core/devicetree_lint.py +168 -0
- tan/core/dir_removal.py +229 -0
- tan/core/doctor_git.py +172 -0
- tan/core/doctor_libraries.py +253 -0
- tan/core/doctor_render.py +185 -0
- tan/core/doctor_scope.py +66 -0
- tan/core/doctor_setools.py +237 -0
- tan/core/doctor_stale.py +180 -0
- tan/core/document_guards.py +723 -0
- tan/core/dp_id.py +97 -0
- tan/core/elf_load.py +63 -0
- tan/core/error_catalog.py +171 -0
- tan/core/example_catalog.py +499 -0
- tan/core/example_facets.py +151 -0
- tan/core/faultdecode.py +521 -0
- tan/core/flash_plan.py +2501 -0
- tan/core/flow_d_report.py +381 -0
- tan/core/flow_d_uptime.py +164 -0
- tan/core/fs_confine.py +130 -0
- tan/core/global_flags.py +230 -0
- tan/core/host_python.py +210 -0
- tan/core/image_bundle.py +247 -0
- tan/core/inert.py +147 -0
- tan/core/jlink_binary.py +128 -0
- tan/core/jlink_probe.py +481 -0
- tan/core/jsonc_splice.py +404 -0
- tan/core/launch_provenance.py +257 -0
- tan/core/link_refusal.py +76 -0
- tan/core/metadata_schema.py +376 -0
- tan/core/model_check.py +227 -0
- tan/core/model_device.py +449 -0
- tan/core/model_doctor.py +198 -0
- tan/core/model_host.py +48 -0
- tan/core/model_list.py +112 -0
- tan/core/model_zoo.py +353 -0
- tan/core/module_template.py +340 -0
- tan/core/mram_link.py +87 -0
- tan/core/new_som_ospi.py +94 -0
- tan/core/os_class.py +159 -0
- tan/core/patch_paths.py +87 -0
- tan/core/pending.py +40 -0
- tan/core/plain_zephyr_plan.py +138 -0
- tan/core/plan_exec.py +373 -0
- tan/core/plan_tokens.py +600 -0
- tan/core/probe.py +155 -0
- tan/core/probe_plan.py +237 -0
- tan/core/proxy.py +168 -0
- tan/core/publish.py +31 -0
- tan/core/python_floor.py +178 -0
- tan/core/ram_run.py +694 -0
- tan/core/ram_watch.py +231 -0
- tan/core/raw_write.py +160 -0
- tan/core/reset_plan.py +56 -0
- tan/core/run.py +161 -0
- tan/core/scaffold.py +2203 -0
- tan/core/scaffold_selftest_identity.py +225 -0
- tan/core/sdk_default_registry.py +565 -0
- tan/core/sdk_discovery.py +996 -0
- tan/core/sdk_removal.py +465 -0
- tan/core/serial_actions.py +175 -0
- tan/core/serial_capture.py +185 -0
- tan/core/serial_url.py +45 -0
- tan/core/setools.py +608 -0
- tan/core/setools_scratch.py +243 -0
- tan/core/shapes.py +194 -0
- tan/core/size.py +610 -0
- tan/core/som_buildability.py +204 -0
- tan/core/som_schema_version.py +62 -0
- tan/core/subprocess_env.py +201 -0
- tan/core/sysbuild_image.py +94 -0
- tan/core/system_manifest.py +827 -0
- tan/core/text_layout.py +73 -0
- tan/core/timestamp.py +182 -0
- tan/core/tool_lookup.py +383 -0
- tan/core/toolchain_pin.py +117 -0
- tan/core/toolchain_provision.py +1224 -0
- tan/core/trusted_path.py +134 -0
- tan/core/uboot_breakin.py +154 -0
- tan/core/uri_reference.py +415 -0
- tan/core/user_defines.py +152 -0
- tan/core/venv.py +332 -0
- tan/core/west_patches.py +143 -0
- tan/core/west_workspace_refusal.py +159 -0
- tan/core/zephyr_env.py +124 -0
- tan/env.py +185 -0
- tan/envelope.py +647 -0
- tan/exit_codes.py +12 -0
- tan/lazy_typer.py +185 -0
- tan/model/__init__.py +2 -0
- tan/model/_gen_fixture.py +132 -0
- tan/model/adapters/__init__.py +116 -0
- tan/model/adapters/cpu.py +26 -0
- tan/model/adapters/deepx.py +94 -0
- tan/model/adapters/drpai.py +242 -0
- tan/model/adapters/ethos_u.py +951 -0
- tan/model/adapters/executorch.py +55 -0
- tan/model/analyze.py +694 -0
- tan/model/build.py +304 -0
- tan/model/check.py +682 -0
- tan/model/manifest.py +625 -0
- tan/model/measure.py +216 -0
- tan/model/npu_ops_validate.py +130 -0
- tan/model/package.py +125 -0
- tan/model/perf.py +635 -0
- tan/model/perf_apply.py +721 -0
- tan/model/prep.py +193 -0
- tan/model/sram_fit.py +502 -0
- tan/model/targets.py +374 -0
- tan/model/tensorio.py +287 -0
- tan/net.py +73 -0
- tan/output_format.py +213 -0
- tan/planner/__init__.py +219 -0
- tan/planner/aperture.py +202 -0
- tan/planner/buildplan.py +1092 -0
- tan/planner/camera_owner.py +192 -0
- tan/planner/cameras.py +132 -0
- tan/planner/carveout.py +755 -0
- tan/planner/cli.py +274 -0
- tan/planner/headers.py +315 -0
- tan/planner/kconfig.py +2435 -0
- tan/planner/kconfig_symbols.py +473 -0
- tan/planner/libraries.py +677 -0
- tan/planner/link_target.py +237 -0
- tan/planner/linux_ownership.py +216 -0
- tan/planner/loader.py +1525 -0
- tan/planner/manifest.py +116 -0
- tan/planner/memory.py +161 -0
- tan/planner/memregion.py +56 -0
- tan/planner/models.py +533 -0
- tan/planner/orchestrator.py +874 -0
- tan/planner/ownership.py +203 -0
- tan/planner/partition.py +1160 -0
- tan/planner/paths.py +32 -0
- tan/planner/plain_slice.py +139 -0
- tan/planner/project_emit/__init__.py +60 -0
- tan/planner/project_emit/bom_netlist.py +375 -0
- tan/planner/project_emit/dts.py +580 -0
- tan/planner/project_emit/hw_info.py +221 -0
- tan/planner/project_emit/native_sim.py +136 -0
- tan/planner/project_emit/west_libs.py +213 -0
- tan/planner/project_loader.py +264 -0
- tan/planner/sdk_capability.py +203 -0
- tan/planner/sdk_compat.py +395 -0
- tan/planner/secure.py +350 -0
- tan/planner/slugs.py +394 -0
- tan/planner/som_metadata.py +325 -0
- tan/planner/strict_loaders.py +131 -0
- tan/planner/template.py +1037 -0
- tan/planner/template_pins.py +535 -0
- tan/planner/template_rewrite.py +714 -0
- tan/planner/topology.py +208 -0
- tan/planner/validate.py +365 -0
- tan/planner/whole_device_alias.py +67 -0
- tan/planner/zephyr_board.py +3510 -0
- tan/planner_cli.py +97 -0
- tan/planner_emit.py +617 -0
- tan/planner_root.py +119 -0
- tan/soc_ref.py +58 -0
- tan/templates/__init__.py +34 -0
- tan/templates/vendored/MANIFEST.md +1862 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
- tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
- tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
- tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
- tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
- tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
- tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
- tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
- tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
- tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
- tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
- tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
- tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
- tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
- tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
- tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
- tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
- tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
- tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
- tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
- tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
- tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
- tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
- tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
- tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
- tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
- tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
- tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
- tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
- tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
- tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
- tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
- tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
- tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
- tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
- tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
- tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
- tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
- tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
- tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
- tan/version.py +102 -0
- tan_cli-0.7.0.dist-info/METADATA +125 -0
- tan_cli-0.7.0.dist-info/RECORD +330 -0
- tan_cli-0.7.0.dist-info/WHEEL +5 -0
- tan_cli-0.7.0.dist-info/entry_points.txt +2 -0
- tan_cli-0.7.0.dist-info/top_level.txt +1 -0
tan/planner/manifest.py
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""System-manifest emitter -- assembles system-manifest.yaml from the model.
|
|
4
|
+
|
|
5
|
+
`emit_system_manifest` renders the spec-§5.2 manifest (slices, carve-outs,
|
|
6
|
+
storage, memory regions, helper-MCU block) off the parsed BoardProject + the
|
|
7
|
+
resolved carve-outs / partitions / memory regions; `_helper_mcus` builds the
|
|
8
|
+
manifest's `helper_mcus[]` block (shared with the Orchestrator's materialise
|
|
9
|
+
path, which back-imports it). Extracted as the #285 manifest emit seam.
|
|
10
|
+
|
|
11
|
+
`memory[]` is the region table the other two panes refer INTO by name
|
|
12
|
+
(#1365 item 3) -- `memory.resolve_memory_regions` shapes it, and it is
|
|
13
|
+
OMITTED rather than emitted empty when a SoM resolves no regions.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from typing import Any, Optional
|
|
19
|
+
|
|
20
|
+
import yaml
|
|
21
|
+
|
|
22
|
+
from .carveout import resolve_carve_outs
|
|
23
|
+
from .memory import resolve_memory_regions
|
|
24
|
+
from .models import BoardProject, Slice, SystemManifest
|
|
25
|
+
from .partition import resolve_storage_partitions
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def emit_system_manifest(
|
|
29
|
+
project: BoardProject,
|
|
30
|
+
*,
|
|
31
|
+
slices: Optional[list[Slice]] = None,
|
|
32
|
+
) -> str:
|
|
33
|
+
"""Generate system-manifest.yaml per spec §5.2.
|
|
34
|
+
|
|
35
|
+
If `slices` is None, projects the BoardProject's `cores` dict
|
|
36
|
+
as-is (typical "describe what will run" call). When the
|
|
37
|
+
orchestrator finishes fan_out it passes its updated Slice list
|
|
38
|
+
so the manifest carries status / log_path / etc.
|
|
39
|
+
"""
|
|
40
|
+
carve_outs = resolve_carve_outs(project)
|
|
41
|
+
partitions = resolve_storage_partitions(project)
|
|
42
|
+
memory_regions = resolve_memory_regions(project)
|
|
43
|
+
effective_slices = list(slices) if slices is not None else list(project.cores.values())
|
|
44
|
+
|
|
45
|
+
boot_order = list(project.som_preset.get("boot_order") or [])
|
|
46
|
+
|
|
47
|
+
manifest = SystemManifest(
|
|
48
|
+
project=project,
|
|
49
|
+
slices=effective_slices,
|
|
50
|
+
carve_outs=carve_outs,
|
|
51
|
+
partitions=partitions,
|
|
52
|
+
boot_order=boot_order,
|
|
53
|
+
helper_mcus=_helper_mcus(project),
|
|
54
|
+
memory_regions=memory_regions,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
out = manifest.to_dict()
|
|
58
|
+
# Comment when boot_order is empty so reviewers see the gap.
|
|
59
|
+
text = yaml.safe_dump(out, sort_keys=False, default_flow_style=False)
|
|
60
|
+
if not boot_order:
|
|
61
|
+
text += ("\n# boot_order is empty -- add a `boot_order:` list to "
|
|
62
|
+
f"metadata/e1m_modules/{project.sku}.yaml when the\n"
|
|
63
|
+
"# bring-up order is finalised.\n")
|
|
64
|
+
return text
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _helper_mcus(project: BoardProject) -> list[dict[str, Any]]:
|
|
68
|
+
"""Build the manifest's `helper_mcus[]` block.
|
|
69
|
+
|
|
70
|
+
Source: the SoM preset's `helper_firmware:` list (Phase 3). Each key
|
|
71
|
+
the entry declares is projected INDEPENDENTLY -- how the image is
|
|
72
|
+
written locally (flash_method + flash_args), how it is updated in the
|
|
73
|
+
field (update_channel), and who may invoke the flash method
|
|
74
|
+
(flash_policy) are three separate axes, and a helper may declare any
|
|
75
|
+
combination. The GD32 bridge declares two: an `alp_ota_spi_bridge`
|
|
76
|
+
channel for normal field updates, and (until tan-cli#732 removed its
|
|
77
|
+
local write path, `swd_probe`) a `recovery_only` local flash method for
|
|
78
|
+
a bricked board. Dropping the flash keys because a channel exists would
|
|
79
|
+
DELETE that recovery path from the manifest rather than let `tan flash`
|
|
80
|
+
decline it, so this function must never make one key's presence
|
|
81
|
+
suppress another's (alp-sdk #1357). `firmware_path` is entirely ABSENT
|
|
82
|
+
from the row when
|
|
83
|
+
the preset doesn't declare one (e.g. GD32 bridge SKUs pending a
|
|
84
|
+
released binary, alp-sdk #852/#936) -- it is never emitted as `null`,
|
|
85
|
+
because `system-manifest-v1.schema.json` types it `string` when present
|
|
86
|
+
(the orchestrator does NOT fail the build on a missing helper firmware
|
|
87
|
+
path -- the Renesas + Alif flash flows are independently scriptable).
|
|
88
|
+
|
|
89
|
+
Every in-tree SoM preset carries a `helper_firmware:` list (no more
|
|
90
|
+
Phase-1 stragglers), so there is no back-compat `on_module.{
|
|
91
|
+
supervisor_mcu,wifi_ble}` fallback here -- no-legacy-compat.
|
|
92
|
+
"""
|
|
93
|
+
out: list[dict[str, Any]] = []
|
|
94
|
+
|
|
95
|
+
helper_firmware = project.som_preset.get("helper_firmware")
|
|
96
|
+
if isinstance(helper_firmware, list):
|
|
97
|
+
for entry in helper_firmware:
|
|
98
|
+
if not isinstance(entry, dict):
|
|
99
|
+
continue
|
|
100
|
+
row: dict[str, Any] = {
|
|
101
|
+
"name": entry.get("name"),
|
|
102
|
+
"chip": entry.get("chip"),
|
|
103
|
+
}
|
|
104
|
+
# Project every declared key independently. No key's presence
|
|
105
|
+
# suppresses another's: `update_channel` describes field
|
|
106
|
+
# updates, `flash_method`/`flash_args` describe a local write,
|
|
107
|
+
# and `flash_policy` says who may perform that write. A helper
|
|
108
|
+
# declaring both halves keeps both -- `tan flash` decides what
|
|
109
|
+
# to do with them from `flash_policy` (alp-sdk #1357).
|
|
110
|
+
for key in ("firmware_path", "flash_method", "flash_args",
|
|
111
|
+
"flash_policy", "update_channel"):
|
|
112
|
+
value = entry.get(key)
|
|
113
|
+
if value is not None:
|
|
114
|
+
row[key] = value
|
|
115
|
+
out.append(row)
|
|
116
|
+
return out
|
tan/planner/memory.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Resolved memory-region view for the system manifest (alp-sdk#1365 item 3).
|
|
4
|
+
|
|
5
|
+
`resolve_memory_regions()` projects the SoM's effective memory-region table
|
|
6
|
+
into the `memory[]` pane `system-manifest-v1` declares -- the third pane
|
|
7
|
+
`ipc[]` and `storage[]` refer INTO by name, not a third copy of them.
|
|
8
|
+
|
|
9
|
+
Three vocabularies, each taken from what the code already produces rather
|
|
10
|
+
than from #1365's issue body (which predates splits A and B and proposes
|
|
11
|
+
shapes the shipped derivation cannot fill):
|
|
12
|
+
|
|
13
|
+
* `kind` is `aperture.classify_region()`'s own four verdicts --
|
|
14
|
+
`flash` / `ram` / `unclassified` / `unresolved`. Collapsing them onto the
|
|
15
|
+
issue's two (`ram` | `flash`) would have to invent a class for the two
|
|
16
|
+
verdicts that exist precisely to say "not proven": `unclassified` (outside
|
|
17
|
+
the aperture AND preset-authored -- an Ensemble OSPI XIP window is outside
|
|
18
|
+
and still flash) and `unresolved` (no extent, or no aperture declared for
|
|
19
|
+
this SoC at all, which is every non-Alif SoM).
|
|
20
|
+
|
|
21
|
+
* the authority field is `write_authority`, passed through verbatim with
|
|
22
|
+
som-preset-v2's six values. The issue's 3-value `owner` was replaced
|
|
23
|
+
during review because one axis cannot separate flash-time from runtime
|
|
24
|
+
authority: `customer_image` and `customer_runtime` would both collapse to
|
|
25
|
+
`customer`, which is the exact distinction the AEN `storage`-vs-`he_slot0`
|
|
26
|
+
hazard needs. A row that authors no `write_authority` carries no key --
|
|
27
|
+
absent means unresolved, never `customer_runtime` (ADR-0034 clause 4).
|
|
28
|
+
|
|
29
|
+
* `status` is `ok` / `unresolved`, the word this schema's own items
|
|
30
|
+
description already made normative, not `ipc[]`'s `ok` / `blocked`. They
|
|
31
|
+
are not synonyms: `blocked` is a verdict about an allocation request,
|
|
32
|
+
while a region is a fact that either resolved an address or did not.
|
|
33
|
+
|
|
34
|
+
`source` is derived here rather than tagged in `alp_project.resolve_memory_map`
|
|
35
|
+
on purpose. That function's precedence is ALL-OR-NOTHING (an authored
|
|
36
|
+
`memory_map:` wins the whole table, else the SoC's fixed `memory_regions`,
|
|
37
|
+
else the silicon-variant derivation), so provenance is a property of the
|
|
38
|
+
table, not of a row -- `carveout.py` and `partition.py` already read it the
|
|
39
|
+
same way, via `bool(som_preset.get("memory_map"))`. Tagging rows inside the
|
|
40
|
+
loader would also add a key to dicts that flow into `$defs/memory_region`'s
|
|
41
|
+
`additionalProperties: false` validation path.
|
|
42
|
+
|
|
43
|
+
Depends only downward -- `som_metadata`, `aperture` and `memregion`; nothing
|
|
44
|
+
calls back into the package.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
|
|
49
|
+
from typing import Any, Optional
|
|
50
|
+
|
|
51
|
+
from .aperture import classify_region, resolve_aperture
|
|
52
|
+
from .memregion import _region_size_bytes
|
|
53
|
+
from .models import BoardProject
|
|
54
|
+
from .som_metadata import resolve_memory_map
|
|
55
|
+
|
|
56
|
+
# The two provenance values a region row can carry. `board_yaml` (the third
|
|
57
|
+
# value #1365's issue body proposes) has no producer: board.yaml never
|
|
58
|
+
# AUTHORS a region, it only NAMES one via `ipc[].carve_out_region` /
|
|
59
|
+
# `storage[].flash_device`, so a board_yaml-sourced region row cannot occur.
|
|
60
|
+
_SOURCE_PRESET = "som_preset"
|
|
61
|
+
_SOURCE_SOC = "soc_derived"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def resolve_memory_regions(project: BoardProject) -> list[dict[str, Any]]:
|
|
65
|
+
"""Project the SoM's memory regions into the manifest's `memory[]` pane.
|
|
66
|
+
|
|
67
|
+
Returns `[]` when the SoM resolves no regions at all (an unresolvable
|
|
68
|
+
`silicon_variant`, e.g. `TBD`). The caller must then OMIT the
|
|
69
|
+
key rather than emit `memory: []` -- the schema draws a load-bearing
|
|
70
|
+
distinction between an absent pane ("this producer does not emit it
|
|
71
|
+
yet") and an empty one, and collapsing the two would tell every
|
|
72
|
+
consumer that a SoM with a pending HW-config writeup has no memory.
|
|
73
|
+
"""
|
|
74
|
+
metadata_root = project.effective_metadata_root()
|
|
75
|
+
memory_map = resolve_memory_map(project.som_preset, metadata_root)
|
|
76
|
+
if not memory_map:
|
|
77
|
+
return []
|
|
78
|
+
|
|
79
|
+
# Same two signals `carveout.py` / `partition.py` derive, read the same
|
|
80
|
+
# way: the SoC's declared on-die flash aperture (None on every non-Alif
|
|
81
|
+
# SoM), and whether THIS preset authored the table.
|
|
82
|
+
aperture = resolve_aperture(project.som_preset, metadata_root)
|
|
83
|
+
is_preset_authored = bool(project.som_preset.get("memory_map"))
|
|
84
|
+
source = _SOURCE_PRESET if is_preset_authored else _SOURCE_SOC
|
|
85
|
+
|
|
86
|
+
return [
|
|
87
|
+
_resolved_row(region, aperture, is_preset_authored, source)
|
|
88
|
+
for region in memory_map
|
|
89
|
+
if isinstance(region, dict) and region.get("name")
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _resolved_row(
|
|
94
|
+
region: dict[str, Any],
|
|
95
|
+
aperture: Optional[tuple[int, int]],
|
|
96
|
+
is_preset_authored: bool,
|
|
97
|
+
source: str,
|
|
98
|
+
) -> dict[str, Any]:
|
|
99
|
+
"""Shape one region into a manifest row.
|
|
100
|
+
|
|
101
|
+
Key order is deliberate and load-bearing for the byte-golden `.snap`
|
|
102
|
+
fixtures: identity first (`name`, `source`), then the two derived
|
|
103
|
+
verdicts (`kind`, `status`), then the resolved numbers, then the
|
|
104
|
+
authored passthroughs, then the explanation. Builds a NEW dict --
|
|
105
|
+
the loader's region dicts are never mutated.
|
|
106
|
+
"""
|
|
107
|
+
row: dict[str, Any] = {
|
|
108
|
+
"name": str(region.get("name")),
|
|
109
|
+
"source": source,
|
|
110
|
+
"kind": classify_region(region, aperture, is_preset_authored),
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# `status` keys off the BASE, not off the extent: a region whose base
|
|
114
|
+
# resolves but whose size does not has still resolved its address, and
|
|
115
|
+
# the schema's rule is written about `base` ("carries no `base` and says
|
|
116
|
+
# why"). `region_extent()` folds both into one None, so it cannot
|
|
117
|
+
# answer this question on its own.
|
|
118
|
+
base = region.get("base")
|
|
119
|
+
base_ok = isinstance(base, int) and not isinstance(base, bool)
|
|
120
|
+
row["status"] = "ok" if base_ok else "unresolved"
|
|
121
|
+
if base_ok:
|
|
122
|
+
row["base"] = base
|
|
123
|
+
|
|
124
|
+
size_bytes = _region_size_bytes(region)
|
|
125
|
+
if size_bytes is not None:
|
|
126
|
+
row["size_bytes"] = size_bytes
|
|
127
|
+
|
|
128
|
+
write_authority = region.get("write_authority")
|
|
129
|
+
if isinstance(write_authority, str) and write_authority:
|
|
130
|
+
row["write_authority"] = write_authority
|
|
131
|
+
|
|
132
|
+
accessible_from = region.get("accessible_from")
|
|
133
|
+
if isinstance(accessible_from, list) and accessible_from:
|
|
134
|
+
row["accessible_from"] = [str(core) for core in accessible_from]
|
|
135
|
+
|
|
136
|
+
if not base_ok:
|
|
137
|
+
row["reason"] = _unresolved_reason(row["name"], base, size_bytes)
|
|
138
|
+
|
|
139
|
+
return row
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _unresolved_reason(name: str, base: Any, size_bytes: Optional[int]) -> str:
|
|
143
|
+
"""Say WHY a base did not resolve, in terms the author can act on.
|
|
144
|
+
|
|
145
|
+
Never a guessed address (ADR-0034 clause 4): the reason names the field
|
|
146
|
+
that is missing and where to declare it, which is what makes an
|
|
147
|
+
unresolved row actionable instead of merely absent.
|
|
148
|
+
"""
|
|
149
|
+
if base is None:
|
|
150
|
+
cause = ("carries no `base:` -- the silicon default applies and no "
|
|
151
|
+
"address is declared for it")
|
|
152
|
+
elif isinstance(base, str):
|
|
153
|
+
cause = f"declares `base: {base}`, a placeholder, not an address"
|
|
154
|
+
else:
|
|
155
|
+
cause = f"declares a non-integer `base:` ({type(base).__name__})"
|
|
156
|
+
sizing = (" Its size resolves, so only the address is missing."
|
|
157
|
+
if size_bytes is not None else
|
|
158
|
+
" Neither its address nor its size resolves.")
|
|
159
|
+
return (f"Region '{name}' {cause}, so no extent can be resolved and no "
|
|
160
|
+
f"class derived.{sizing} Declare `base:` in this SoM preset's "
|
|
161
|
+
f"`memory_map:` to resolve it.")
|
tan/planner/memregion.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""Memory-region math shared across the resolvers -- a leaf.
|
|
4
|
+
|
|
5
|
+
The page granularity and the memory_map size-field -> bytes conversion, used by
|
|
6
|
+
both the carve-out resolver and the storage-partition resolver. A dependency-
|
|
7
|
+
free leaf (typing only) so each resolver imports it directly instead of one
|
|
8
|
+
reaching into the other (or back through the package __init__). Extracted as a
|
|
9
|
+
#285 leaf seam -- the same move as paths.py -- so the partition resolver lands
|
|
10
|
+
cleanly.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, Optional
|
|
16
|
+
|
|
17
|
+
# Page granularity for carve-out / partition base + size alignment.
|
|
18
|
+
_PAGE = 4096
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _region_size_bytes(region: dict[str, Any]) -> Optional[int]:
|
|
22
|
+
"""Convert a memory_map entry's size_mib / size_kib to bytes.
|
|
23
|
+
|
|
24
|
+
Reads each field by its VALUE, not by key presence: the
|
|
25
|
+
`memory_region` schema lets `size_kib` and `size_mib` each
|
|
26
|
+
independently be an int or the literal `"TBD"`, so a `"TBD"` in one
|
|
27
|
+
field must never mask a usable integer sitting in the other (e.g.
|
|
28
|
+
`{size_mib: "TBD", size_kib: 64}` must resolve via `size_kib`, not
|
|
29
|
+
bail out because `size_mib` is present but unresolved). `size_mib`
|
|
30
|
+
is checked first -- matching this module's real prior behaviour: on
|
|
31
|
+
`origin/dev` before alp-sdk#1365 split B, this function's only two
|
|
32
|
+
callers (`carveout.py` and `partition.py`) both went through a
|
|
33
|
+
key-PRESENCE check that looked at `size_mib` first
|
|
34
|
+
(`if "size_mib" in region: ...`). `check_atoc_reservation.py` was
|
|
35
|
+
NOT a caller of this module then -- it carried its own private,
|
|
36
|
+
unrelated `_region_size_kib` helper (kib-first), which split B
|
|
37
|
+
retired in favour of importing this module instead. That gate
|
|
38
|
+
becoming a caller here is what split B changed; it is not evidence
|
|
39
|
+
of this module's own prior precedence, which was mib-first.
|
|
40
|
+
|
|
41
|
+
The schema permits both fields on one region (neither `som-preset-
|
|
42
|
+
v1.schema.json`'s `memory_region` nor `soc-spec-v1.schema.json`'s
|
|
43
|
+
forbids it), and no region in `metadata/e1m_modules/*.yaml` today
|
|
44
|
+
sets both, so this precedence has no real-preset evidence either
|
|
45
|
+
way -- pinned here by test only, matching the module's actual
|
|
46
|
+
history rather than a caller that did not exist yet.
|
|
47
|
+
|
|
48
|
+
Returns None only when NEITHER field resolves to a usable integer.
|
|
49
|
+
"""
|
|
50
|
+
size_mib = region.get("size_mib")
|
|
51
|
+
if isinstance(size_mib, int) and not isinstance(size_mib, bool):
|
|
52
|
+
return size_mib * 1024 * 1024
|
|
53
|
+
size_kib = region.get("size_kib")
|
|
54
|
+
if isinstance(size_kib, int) and not isinstance(size_kib, bool):
|
|
55
|
+
return size_kib * 1024
|
|
56
|
+
return None
|