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
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""`tan flash --ram` -- AEN Flow C: J-Link ITCM RAM-run + RAM-console read
|
|
3
|
+
(tan-cli#1313).
|
|
4
|
+
|
|
5
|
+
**Why `flash --ram` and not `run --ram`.** `tan run` is a thin orchestrator that
|
|
6
|
+
builds and then delegates to this command's engine; everything Flow C needs --
|
|
7
|
+
the probe-selection guard (tan-cli#1312), the DPIDR preflight, the trusted J-Link
|
|
8
|
+
binary (tan-cli#1336), `--dry-run`, `--jlink`, the per-run envelope -- already
|
|
9
|
+
lives behind `tan flash`. A `run --ram` would re-expose a third copy of it.
|
|
10
|
+
|
|
11
|
+
**What it does** (the proven raw recipe is alp-sdk `scripts/bench/aen/ram-run.sh`):
|
|
12
|
+
|
|
13
|
+
1. read the slice's ELF and its sibling `zephyr.bin`; the load address is DERIVED
|
|
14
|
+
from the ELF's LOAD segments and the image is refused unless it is linked for
|
|
15
|
+
ITCM/SRAM (`tan.core.ram_run.plan_ram_image`) -- an MRAM-linked image would just
|
|
16
|
+
re-enter the resident MRAM image;
|
|
17
|
+
2. verify the probe (the same `_ProbeGuard` as a Flow D write: ShowEmuList, TOCTOU
|
|
18
|
+
re-check, shared-serial handshake, `exec DisableAutoUpdateFW`), run the read-only
|
|
19
|
+
DPIDR preflight when `expect_dpidr`/`jlink_device` arm it, then ONE J-Link session:
|
|
20
|
+
`connect; halt; loadbin zephyr.bin <base>; setpc <reset handler>; go`. `loadbin`
|
|
21
|
+
resets the core, which loads SP from the vector table; the PC is set from the
|
|
22
|
+
vector table's reset handler (refused if it disagrees with the ELF entry).
|
|
23
|
+
`WReg` is not accepted by J-Link Commander here (bench notes), so SP is not
|
|
24
|
+
written by hand -- the vector-table SP is reported, not applied;
|
|
25
|
+
3. with `--ram-console`, wait `--wait` seconds and read `ram_console_buf`
|
|
26
|
+
(address and size from the ELF symbol, never hardcoded) in a second session
|
|
27
|
+
through `mem8`, decode it and report it.
|
|
28
|
+
|
|
29
|
+
**Nothing writes MRAM**: the only addresses in the script are the ITCM/SRAM load
|
|
30
|
+
base and the console buffer, and an MRAM-linked image is refused.
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import contextlib
|
|
35
|
+
import os
|
|
36
|
+
import re
|
|
37
|
+
import shutil
|
|
38
|
+
import tempfile
|
|
39
|
+
import time
|
|
40
|
+
from typing import Any
|
|
41
|
+
|
|
42
|
+
from tan.commands import flash_cmd as fc
|
|
43
|
+
from tan.core.flash_plan import (
|
|
44
|
+
FLOW_D_METHOD,
|
|
45
|
+
FlashInputs,
|
|
46
|
+
FlashPlan,
|
|
47
|
+
FlashPlanError,
|
|
48
|
+
FlashTarget,
|
|
49
|
+
_DEFAULT_JLINK_SPEED,
|
|
50
|
+
commander_path,
|
|
51
|
+
confirm_gate_note,
|
|
52
|
+
dpidr_preflight_unarmed,
|
|
53
|
+
fa_bool_checked,
|
|
54
|
+
fa_int_checked,
|
|
55
|
+
fa_str,
|
|
56
|
+
fa_str_checked,
|
|
57
|
+
validate_commander_path,
|
|
58
|
+
validate_identifier,
|
|
59
|
+
)
|
|
60
|
+
from tan.core.jlink_binary import resolve_jlink
|
|
61
|
+
from tan.core import ram_watch
|
|
62
|
+
from tan.core.ram_run import (
|
|
63
|
+
CODE_CONSOLE_SYMBOL_MISSING,
|
|
64
|
+
CODE_CORE_MISMATCH,
|
|
65
|
+
CODE_CORE_UNCONFIRMED,
|
|
66
|
+
OVERRIDABLE_VERDICTS,
|
|
67
|
+
trouble_markers,
|
|
68
|
+
ap_verdict,
|
|
69
|
+
core_check,
|
|
70
|
+
core_check_script,
|
|
71
|
+
apertures_for,
|
|
72
|
+
attached_core,
|
|
73
|
+
CODE_FAILED,
|
|
74
|
+
CONSOLE_SYMBOL,
|
|
75
|
+
RamRunError,
|
|
76
|
+
check_session,
|
|
77
|
+
decode_console,
|
|
78
|
+
load_script,
|
|
79
|
+
parse_elf,
|
|
80
|
+
plan_ram_image,
|
|
81
|
+
preamble,
|
|
82
|
+
read_back,
|
|
83
|
+
read_script,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
#: The `method` this entry reports.
|
|
87
|
+
METHOD = "ram_run"
|
|
88
|
+
#: Default `--wait` (seconds the app runs before the console is read) -- the raw
|
|
89
|
+
#: script's `sleep_ms` default of 1500.
|
|
90
|
+
DEFAULT_WAIT_S = 1.5
|
|
91
|
+
#: Experimental (tan-cli#1372 ask 2, pending bench A/B): keep the load session open for
|
|
92
|
+
#: the `--wait` window after `go` and skip the separate pre-read wait.
|
|
93
|
+
HOLD_ENV = "TAN_FLASH_RAM_HOLD"
|
|
94
|
+
#: J-Link's own attach profile for a live core (the script's `JLINK_DEVICE_READ`).
|
|
95
|
+
_DEFAULT_ATTACH_DEVICE = "Cortex-M55"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _artefact_pair(path: str) -> tuple[str, str]:
|
|
99
|
+
"""`(elf, bin)` for a manifest artefact: `zephyr.elf` + `zephyr.bin`."""
|
|
100
|
+
stem, ext = os.path.splitext(path)
|
|
101
|
+
elf = path if ext.lower() == ".elf" else stem + ".elf"
|
|
102
|
+
return elf, os.path.splitext(elf)[0] + ".bin"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _read(path: str) -> bytes:
|
|
106
|
+
with open(path, "rb") as fh:
|
|
107
|
+
return fh.read()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def run_ram_entry(target: FlashTarget, ctx: Any) -> tuple[int, Any, list[str]]:
|
|
111
|
+
"""RAM-run one slice. Returns `(rc, entry, text-lines)` like `_flash_entry`."""
|
|
112
|
+
with contextlib.ExitStack() as stack:
|
|
113
|
+
return _run_ram_entry(target, ctx, stack)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _stage_image(stack: contextlib.ExitStack, data: bytes) -> str:
|
|
117
|
+
"""Write the image to a TAN-OWNED temp file with a fixed safe name and return its
|
|
118
|
+
path -- the ONLY path that is ever interpolated into the Commander `loadbin`
|
|
119
|
+
line, so a project-controlled artefact path (newline, quote, `;`) can never reach
|
|
120
|
+
the script. Removed when the entry ends."""
|
|
121
|
+
directory = tempfile.mkdtemp(prefix="tan-ram-")
|
|
122
|
+
stack.callback(shutil.rmtree, directory, True)
|
|
123
|
+
path = os.path.join(directory, "image.bin")
|
|
124
|
+
with open(path, "wb") as fh:
|
|
125
|
+
fh.write(data)
|
|
126
|
+
validate_commander_path(path, "the staged RAM image path")
|
|
127
|
+
return path
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _run_ram_entry(
|
|
131
|
+
target: FlashTarget, ctx: Any, stack: contextlib.ExitStack
|
|
132
|
+
) -> tuple[int, Any, list[str]]:
|
|
133
|
+
kind, entry_id = target.kind, target.id
|
|
134
|
+
lines: list[str] = [f"flash: {kind} '{entry_id}' -> {METHOD}"]
|
|
135
|
+
report: dict[str, Any] = {}
|
|
136
|
+
probe_echo: dict[str, Any] | None = None
|
|
137
|
+
|
|
138
|
+
def entry(status: str, rc: int, message: str, **kw: Any) -> Any:
|
|
139
|
+
return fc._Entry(
|
|
140
|
+
kind=kind, id=entry_id, method=METHOD, status=status, rc=rc, message=message,
|
|
141
|
+
probe=probe_echo, extra=report, **kw,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def fail(message: str, code: str | None = CODE_FAILED, **kw: Any) -> tuple[int, Any, list[str]]:
|
|
145
|
+
text = f"{METHOD}[{entry_id}]: {message}"
|
|
146
|
+
lines.append(f" FAIL: {text}")
|
|
147
|
+
return 1, entry("failed", 1, text, issue_code=code, **kw), lines
|
|
148
|
+
|
|
149
|
+
if kind != "slice":
|
|
150
|
+
return fail("only a slice can be RAM-run, not a helper MCU")
|
|
151
|
+
if not isinstance(target.flash_args, dict) and target.flash_args is not None:
|
|
152
|
+
return fail("flash_args is not a mapping")
|
|
153
|
+
# `--watch` is refused before anything is read or spawned, under --dry-run too.
|
|
154
|
+
watch_ms = int(round(max(ctx.ram_wait, 0.0) * 1000))
|
|
155
|
+
try:
|
|
156
|
+
watches = ram_watch.parse_watches(ctx.ram_watch)
|
|
157
|
+
watch_script = ram_watch.watch_lines(watches, watch_ms) if watches else []
|
|
158
|
+
except ram_watch.WatchError as err:
|
|
159
|
+
return fail(str(err), err.code)
|
|
160
|
+
flash_args: Any = dict(target.flash_args or {})
|
|
161
|
+
|
|
162
|
+
# ── the image ──
|
|
163
|
+
artefact = target.output_artefact
|
|
164
|
+
if not artefact or fc.is_pending(artefact):
|
|
165
|
+
return fail("the slice has no built output_artefact; run `tan build` first")
|
|
166
|
+
elf_path, bin_path = _artefact_pair(
|
|
167
|
+
fc.resolve_artefact_path(artefact, ctx.build_root, ctx.sdk_root, fc._is_file)
|
|
168
|
+
)
|
|
169
|
+
try:
|
|
170
|
+
# Refused before anything is read or spawned: these strings appear in
|
|
171
|
+
# messages and the transcript header, and a control character in a path is
|
|
172
|
+
# never legitimate. (The script itself only ever sees the staged copy.)
|
|
173
|
+
validate_commander_path(elf_path, "the ELF path")
|
|
174
|
+
validate_commander_path(bin_path, "the binary path")
|
|
175
|
+
validate_identifier(entry_id, "the flash target id")
|
|
176
|
+
except FlashPlanError as err:
|
|
177
|
+
return fail(str(err))
|
|
178
|
+
try:
|
|
179
|
+
elf_bytes, bin_bytes = _read(elf_path), _read(bin_path)
|
|
180
|
+
except OSError as err:
|
|
181
|
+
return fail(f"cannot read the built image ({err}); expected {elf_path} and {bin_path}")
|
|
182
|
+
try:
|
|
183
|
+
apertures = _load_apertures(ctx, entry_id)
|
|
184
|
+
image = plan_ram_image(
|
|
185
|
+
parse_elf(elf_bytes), bin_bytes, core_id=entry_id, apertures=apertures
|
|
186
|
+
)
|
|
187
|
+
except RamRunError as err:
|
|
188
|
+
return fail(str(err), err.code)
|
|
189
|
+
|
|
190
|
+
# ── J-Link: trusted binary, probe selection, parameters ──
|
|
191
|
+
found = resolve_jlink(ctx.jlink_path, project_dir=ctx.project_dir)
|
|
192
|
+
exe = found.path if found is not None else None
|
|
193
|
+
report["jlink"] = {"binary": exe, "binarySource": found.source if found else None}
|
|
194
|
+
if exe is None and not ctx.dry_run:
|
|
195
|
+
return fail(fc._NO_TRUSTED_JLINK)
|
|
196
|
+
try:
|
|
197
|
+
flash_args, selection, snapshot = fc._flow_d_probe_selection(flash_args, ctx)
|
|
198
|
+
probe_echo = fc._probe_echo(selection, ctx)
|
|
199
|
+
if selection is not None and selection.refusal_code is not None:
|
|
200
|
+
lines.append(f" FAIL: {selection.refusal}")
|
|
201
|
+
return (
|
|
202
|
+
1,
|
|
203
|
+
entry("failed", 1, selection.refusal or "", probe_refusal=selection.refusal_code),
|
|
204
|
+
lines,
|
|
205
|
+
)
|
|
206
|
+
guard = None
|
|
207
|
+
if selection is not None and (selection.serial is not None or selection.visible is None):
|
|
208
|
+
guard = fc._ProbeGuard(selection, snapshot, ctx.enumerate_probes, probe_echo)
|
|
209
|
+
serial = fa_str_checked(flash_args, "jlink_serial", False)
|
|
210
|
+
device = fa_str(flash_args, "jlink_device") or _DEFAULT_ATTACH_DEVICE
|
|
211
|
+
validate_identifier(device, "jlink_device", destination="a J-Link Commander script line")
|
|
212
|
+
if not device.startswith("Cortex-"):
|
|
213
|
+
# The part-number FLASH profile (`jlink_flash_device`) unlocks the MRAM
|
|
214
|
+
# loader and will not re-halt a running core; the bench's JLINK_DEVICE_READ
|
|
215
|
+
# contract is the generic core profile for every RAM-run attach.
|
|
216
|
+
raise FlashPlanError(
|
|
217
|
+
f"jlink_device '{device}' is a part-number profile, not a generic core "
|
|
218
|
+
f"profile; a RAM-run attaches with '{_DEFAULT_ATTACH_DEVICE}' (the part "
|
|
219
|
+
"profile unlocks the MRAM loader and cannot re-halt a live core)"
|
|
220
|
+
)
|
|
221
|
+
speed = fa_int_checked(flash_args, "jlink_speed") or _DEFAULT_JLINK_SPEED
|
|
222
|
+
if serial is not None:
|
|
223
|
+
validate_identifier(serial, "jlink_serial", destination=fc._JLINK_SERIAL_DESTINATION)
|
|
224
|
+
fc.validate_flow_d_preflight_args(flash_args)
|
|
225
|
+
except FlashPlanError as err:
|
|
226
|
+
return fail(str(err))
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
staged = _stage_image(stack, bin_bytes)
|
|
230
|
+
pre = preamble(serial, speed, device)
|
|
231
|
+
except (OSError, FlashPlanError, RamRunError) as err:
|
|
232
|
+
return fail(f"cannot prepare the RAM-run ({err})")
|
|
233
|
+
# `image.base`/`entry` and the console address/size are ints rendered with
|
|
234
|
+
# `0x%X` by `ram_run`; the symbol NAME never reaches a script at all.
|
|
235
|
+
console = image.console
|
|
236
|
+
# A watch session already spans the whole --wait window, so it needs no extra Sleep.
|
|
237
|
+
hold = (
|
|
238
|
+
os.environ.get(HOLD_ENV) == "1" and bool(ctx.ram_console) and console is not None
|
|
239
|
+
)
|
|
240
|
+
hold_ms = watch_ms if hold and not watches else 0
|
|
241
|
+
load = load_script(pre, commander_path(staged), image, watch_script, hold_ms)
|
|
242
|
+
argv = (
|
|
243
|
+
"JLinkExe", "-device", device, "-if", "SWD", "-speed", str(speed),
|
|
244
|
+
"-ExitOnError", "1", "-NoGui", "1", "-CommanderScript",
|
|
245
|
+
)
|
|
246
|
+
selected = "ram" if console is not None else "uart"
|
|
247
|
+
ram_console: dict[str, Any] = {
|
|
248
|
+
"selected": selected,
|
|
249
|
+
"symbol": CONSOLE_SYMBOL if console else None,
|
|
250
|
+
"address": f"0x{console[0]:08X}" if console else None,
|
|
251
|
+
"size": console[1] if console else None,
|
|
252
|
+
"requested": bool(ctx.ram_console),
|
|
253
|
+
}
|
|
254
|
+
report["ramConsole"] = ram_console
|
|
255
|
+
report["ram"] = {
|
|
256
|
+
"elf": elf_path, "binary": bin_path, "stagedImage": staged, "loadAddress": f"0x{image.base:08X}",
|
|
257
|
+
"size": image.size, "entry": f"0x{image.entry:08X}",
|
|
258
|
+
"initialSp": f"0x{image.initial_sp:08X}",
|
|
259
|
+
"spNote": "from the vector table; applied by loadbin's reset, not written by tan",
|
|
260
|
+
"wait": ctx.ram_wait, "writesMram": False,
|
|
261
|
+
"holdSession": hold,
|
|
262
|
+
}
|
|
263
|
+
if watches:
|
|
264
|
+
report["ram"]["watch"] = {
|
|
265
|
+
"specs": [
|
|
266
|
+
{"address": f"0x{w.address:08X}", "words": w.words, "periodMs": w.period_ms}
|
|
267
|
+
for w in watches
|
|
268
|
+
],
|
|
269
|
+
"durationMs": watch_ms,
|
|
270
|
+
"timeBasis": "scheduled",
|
|
271
|
+
"access": "mem32 (read-only)",
|
|
272
|
+
}
|
|
273
|
+
report["plan"] = {
|
|
274
|
+
"argv": list(argv),
|
|
275
|
+
"jlinkScript": (fc._DISABLE_FW_UPDATE + load).splitlines(),
|
|
276
|
+
"coreCheckScript": (fc._DISABLE_FW_UPDATE + core_check_script(pre)).splitlines(),
|
|
277
|
+
"consoleReadScript": (
|
|
278
|
+
(fc._DISABLE_FW_UPDATE + read_script(pre, *console)).splitlines()
|
|
279
|
+
if console and ctx.ram_console else None
|
|
280
|
+
),
|
|
281
|
+
}
|
|
282
|
+
missing_symbol = bool(ctx.ram_console and console is None)
|
|
283
|
+
warn_missing = {"ram_console_missing": True} if missing_symbol else {}
|
|
284
|
+
summary = (
|
|
285
|
+
f"loaded {image.size} B at 0x{image.base:X}, PC=0x{image.entry:X}, "
|
|
286
|
+
f"SP=0x{image.initial_sp:X} (vector table)"
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
if ctx.dry_run:
|
|
290
|
+
msg = f"{METHOD}[{entry_id}]: would run -- {summary}; no MRAM write; nothing spawned"
|
|
291
|
+
lines.append(f" {msg}")
|
|
292
|
+
return 0, entry("ok", 0, msg, trcena_note=True, trcena_hold=hold, **warn_missing), lines
|
|
293
|
+
|
|
294
|
+
# ── the confirm gate (bench round 7) ──
|
|
295
|
+
# `loadbin` resets the core through AIRCR.SYSRESETREQ, a full-device reset that also
|
|
296
|
+
# resets the Secure Enclave, and the run REPLACES the running image: it is gated like
|
|
297
|
+
# every other write. Without --confirm (or ALP_FLASH_FORCE=1 / flash_args.confirm) it
|
|
298
|
+
# previews and exits non-zero, exactly as an unconfirmed flash does.
|
|
299
|
+
try:
|
|
300
|
+
confirmed = ctx.force_confirm or bool(fa_bool_checked(flash_args, "confirm"))
|
|
301
|
+
except FlashPlanError as err:
|
|
302
|
+
return fail(str(err))
|
|
303
|
+
if not confirmed:
|
|
304
|
+
msg = (
|
|
305
|
+
f"{METHOD}[{entry_id}]: would run -- {summary} -- NOT run: "
|
|
306
|
+
f"{confirm_gate_note('--confirm was not given')}. --ram resets the whole device "
|
|
307
|
+
"(AIRCR.SYSRESETREQ, which resets the Secure Enclave) and replaces the running image."
|
|
308
|
+
)
|
|
309
|
+
lines.append(f" {msg}")
|
|
310
|
+
return 0, entry("planned", 0, msg, **warn_missing), lines
|
|
311
|
+
|
|
312
|
+
# ── the wrong-board guard, exactly as for a Flow D write ──
|
|
313
|
+
armed = not dpidr_preflight_unarmed(FLOW_D_METHOD, flash_args, None)
|
|
314
|
+
if ctx.require_dpidr and not armed:
|
|
315
|
+
return fail(
|
|
316
|
+
"ALP_FLASH_REQUIRE_DPIDR=1 is set and flash_args.expect_dpidr / jlink_device are "
|
|
317
|
+
"not both set -- refusing to run with no wrong-board guard"
|
|
318
|
+
)
|
|
319
|
+
if guard is not None and armed:
|
|
320
|
+
# Verified once up front; the armed DPIDR preflight reuses it (as in Flow D) and
|
|
321
|
+
# the load session re-verifies immediately before ITS spawn.
|
|
322
|
+
refusal = fc._probe_guard_refusal(guard, exe, None, ctx.workspace)
|
|
323
|
+
if refusal is not None:
|
|
324
|
+
return fail(refusal, None, probe_refusal=guard.tripped_code)
|
|
325
|
+
guard.fresh = True
|
|
326
|
+
facts: dict[str, Any] = {}
|
|
327
|
+
refusal = fc._flow_d_preflight(
|
|
328
|
+
FlashInputs(
|
|
329
|
+
artefact=elf_path, flash_args=flash_args, core_id=entry_id, sku=ctx.sku,
|
|
330
|
+
dry_run=False, force_confirm=ctx.force_confirm,
|
|
331
|
+
),
|
|
332
|
+
ctx.venv_bin, ctx.workspace, probe_guard=guard, facts=facts, jlink_exe=exe,
|
|
333
|
+
)
|
|
334
|
+
if refusal is not None:
|
|
335
|
+
tripped = guard is not None and guard.tripped == refusal
|
|
336
|
+
return fail(refusal, None, probe_refusal=guard.tripped_code if tripped else None)
|
|
337
|
+
report["jlink"].update({"dpidr": facts.get("dpidr"), "dpidrSource": "preflight" if facts else "none"})
|
|
338
|
+
report["jlink"]["attachedCore"] = None
|
|
339
|
+
|
|
340
|
+
# ── which core did the generic attach land on? (tan-cli#1354) ──
|
|
341
|
+
# DECISIVE: the AP that reports `Core found` (HE APAddr 0x00300000). CORROBORATION: the
|
|
342
|
+
# local ITCM at 0x0 against the HE window 0x58000000 -- two read-only `mem32`s, no halt,
|
|
343
|
+
# no write, and the HP window is never read. Only an HE access port proceeds; HP
|
|
344
|
+
# evidence refuses and --assume-he can never override it.
|
|
345
|
+
check = fc._execute(
|
|
346
|
+
FlashPlan(argv=argv, ok_message="", jlink_script=core_check_script(pre)),
|
|
347
|
+
True, ctx.venv_bin, ctx.workspace, guard, jlink_exe=exe,
|
|
348
|
+
)
|
|
349
|
+
if guard is not None and guard.tripped:
|
|
350
|
+
return fail(guard.tripped, None, probe_refusal=guard.tripped_code)
|
|
351
|
+
check_text = f"{check.stdout}\n{check.stderr}"
|
|
352
|
+
bad = None if check.success else (fc._capture_tail(check) or "J-Link failed")
|
|
353
|
+
bad = bad or check_session(check_text, loadbin=False)
|
|
354
|
+
if bad:
|
|
355
|
+
verdict, evidence = "unreadable", {}
|
|
356
|
+
else:
|
|
357
|
+
verdict, evidence = core_check(check_text)
|
|
358
|
+
report["ram"]["coreCheck"] = {
|
|
359
|
+
"verdict": verdict, **evidence, "assumeHe": bool(ctx.assume_he),
|
|
360
|
+
"basis": "DECISIVE: the AP that reports `Core found` (HE APAddr 0x00300000, HP "
|
|
361
|
+
"0x00200000); CORROBORATION: local ITCM 0x0 compared with the HE global window "
|
|
362
|
+
"0x58000000 (the HP window is never read)",
|
|
363
|
+
**({"sessionError": bad} if bad else {}),
|
|
364
|
+
}
|
|
365
|
+
report["jlink"]["attachedCore"] = evidence.get("ap")
|
|
366
|
+
# Halt/reset trouble the CHECK session itself reported (it halts nothing, but a
|
|
367
|
+
# core that is already unhaltable says so on connect): reported against the check.
|
|
368
|
+
check_trouble = trouble_markers(check_text)
|
|
369
|
+
report["ram"]["coreCheck"]["resetFailures"] = list(check_trouble)
|
|
370
|
+
if verdict in ("hp", "conflict-hp"):
|
|
371
|
+
return fail(
|
|
372
|
+
"the probe is attached to the M55-HP core (J-Link's Core-found access port is "
|
|
373
|
+
"the HP's 0x00200000"
|
|
374
|
+
+ (", and the local ITCM equals the HE window, which is contradictory" if verdict == "conflict-hp" else "")
|
|
375
|
+
+ ") -- refusing to load the HE image into it. Select the HE core's debug port. "
|
|
376
|
+
"--assume-he never overrides HP evidence.", CODE_CORE_MISMATCH,
|
|
377
|
+
)
|
|
378
|
+
if verdict != "he":
|
|
379
|
+
if not (ctx.assume_he and verdict in OVERRIDABLE_VERDICTS):
|
|
380
|
+
return fail(
|
|
381
|
+
f"cannot confirm the attached core is the M55-HE ({verdict}"
|
|
382
|
+
+ (f": {bad}" if bad else "")
|
|
383
|
+
+ "): "
|
|
384
|
+
+ (
|
|
385
|
+
"the access port says HE but the local ITCM does not equal the HE window "
|
|
386
|
+
"-- contradictory, and not overridable. "
|
|
387
|
+
if verdict == "conflict"
|
|
388
|
+
else "J-Link named no Core-found access port tan can place "
|
|
389
|
+
"(HE 0x00300000), or the check session could not be read. "
|
|
390
|
+
)
|
|
391
|
+
+ "Refusing to load."
|
|
392
|
+
+ (
|
|
393
|
+
" --assume-he overrides this at your own risk (the bench has seen the "
|
|
394
|
+
"generic attach land on HE 6 of 6 times, which is not proof); it never "
|
|
395
|
+
"overrides HP evidence or a contradiction."
|
|
396
|
+
if verdict in OVERRIDABLE_VERDICTS
|
|
397
|
+
else ""
|
|
398
|
+
),
|
|
399
|
+
CODE_CORE_UNCONFIRMED,
|
|
400
|
+
)
|
|
401
|
+
report["ram"]["coreCheck"]["assumed"] = True
|
|
402
|
+
|
|
403
|
+
# ── load + go ──
|
|
404
|
+
plan = FlashPlan(argv=argv, ok_message="", jlink_script=load)
|
|
405
|
+
started = time.monotonic()
|
|
406
|
+
outcome = fc._execute(
|
|
407
|
+
plan, ctx.capture, ctx.venv_bin, ctx.workspace, guard, jlink_exe=exe,
|
|
408
|
+
timeout_s=(
|
|
409
|
+
max(fc._FLASH_TIMEOUT_S, ram_watch.session_timeout_s(watches, watch_ms))
|
|
410
|
+
if watches
|
|
411
|
+
else max(fc._FLASH_TIMEOUT_S, hold_ms / 1000 + ram_watch.TIMEOUT_MARGIN_S)
|
|
412
|
+
if hold_ms
|
|
413
|
+
else None
|
|
414
|
+
),
|
|
415
|
+
)
|
|
416
|
+
spawn_ms = int(round((time.monotonic() - started) * 1000))
|
|
417
|
+
transcript = f"{outcome.stdout}\n{outcome.stderr}"
|
|
418
|
+
_save_transcript(ctx, entry_id, report, load, outcome)
|
|
419
|
+
if guard is not None and guard.tripped:
|
|
420
|
+
return fail(guard.tripped, None, probe_refusal=guard.tripped_code)
|
|
421
|
+
problem = None if outcome.success else (fc._capture_tail(outcome) or "J-Link failed")
|
|
422
|
+
problem = problem or check_session(transcript, loadbin=True)
|
|
423
|
+
if problem:
|
|
424
|
+
return fail(f"the load session failed: {problem}")
|
|
425
|
+
# tan-cli#1497: from here the image IS on the board and the device was reset,
|
|
426
|
+
# whatever fails next; `model run --device` reads this to keep its provenance.
|
|
427
|
+
report["ram"]["loaded"] = True
|
|
428
|
+
loaded_on = attached_core(transcript)
|
|
429
|
+
checked_on = report["jlink"].get("attachedCore")
|
|
430
|
+
if not (loaded_on and loaded_on.get("apAddr")):
|
|
431
|
+
# Not silently skipped: say the load banner named no Core-found AP.
|
|
432
|
+
report["jlink"]["attachedCoreAtLoad"] = None
|
|
433
|
+
report["jlink"]["attachedCoreAtLoadNote"] = (
|
|
434
|
+
"the load transcript named no Core-found access port, so the load session's "
|
|
435
|
+
"core was not compared with the core check's"
|
|
436
|
+
)
|
|
437
|
+
if loaded_on and loaded_on.get("apAddr"):
|
|
438
|
+
# The load is a SEPARATE J-Link session: it can attach to a different AP than the
|
|
439
|
+
# check did (a probe that re-enumerated). After the fact, but loud -- the image may
|
|
440
|
+
# now be in the wrong core. Both attaches are reported.
|
|
441
|
+
report["jlink"]["attachedCoreAtLoad"] = loaded_on
|
|
442
|
+
differs = bool(checked_on) and checked_on.get("apAddr") != loaded_on.get("apAddr")
|
|
443
|
+
if differs or ap_verdict(loaded_on) == "hp":
|
|
444
|
+
return fail(
|
|
445
|
+
f"the load session attached to AP {loaded_on.get('apAddr')} "
|
|
446
|
+
f"({ap_verdict(loaded_on)}) but the core check attached to AP "
|
|
447
|
+
f"{(checked_on or {}).get('apAddr')}: the image may have been loaded into the "
|
|
448
|
+
"WRONG core. Power-cycle the board and check both cores before running "
|
|
449
|
+
"anything else.", CODE_CORE_MISMATCH,
|
|
450
|
+
)
|
|
451
|
+
elif checked_on is None and loaded_on:
|
|
452
|
+
report["jlink"]["attachedCore"] = loaded_on
|
|
453
|
+
if not facts:
|
|
454
|
+
from tan.core.flow_d_report import dpidr_in
|
|
455
|
+
|
|
456
|
+
report["jlink"].update({"dpidr": dpidr_in(transcript), "dpidrSource": "write-transcript"})
|
|
457
|
+
unarmed = not armed
|
|
458
|
+
# Halt/reset trouble is surfaced like Flow D's reset failures (bench round 8): a load
|
|
459
|
+
# that only worked through J-Link's fallback chain is reported, never reported clean.
|
|
460
|
+
trouble = trouble_markers(transcript)
|
|
461
|
+
report["jlink"]["resetFailures"] = list(dict.fromkeys([*check_trouble, *trouble]))
|
|
462
|
+
|
|
463
|
+
# ── the watch samples (tan-cli#1436) ──
|
|
464
|
+
watch_note = None
|
|
465
|
+
if watches:
|
|
466
|
+
samples = ram_watch.parse_samples(transcript, watches, watch_ms)
|
|
467
|
+
report["watch"] = samples
|
|
468
|
+
report["ram"]["watch"]["spawnMs"] = spawn_ms
|
|
469
|
+
missing = sum(1 for s in samples if s["values"] is None)
|
|
470
|
+
if missing == len(samples):
|
|
471
|
+
watch_note = (
|
|
472
|
+
f"{entry_id}: --watch returned NO data: none of the {len(samples)} samples has a "
|
|
473
|
+
"mem32 dump in the J-Link transcript (all values: null); the watched addresses "
|
|
474
|
+
"were not read -- see the transcript"
|
|
475
|
+
)
|
|
476
|
+
elif missing:
|
|
477
|
+
watch_note = (
|
|
478
|
+
f"{entry_id}: {missing} of {len(samples)} --watch samples have no mem32 dump in "
|
|
479
|
+
"the J-Link transcript (values: null); the rest are in data.watch[]"
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
# ── the console ──
|
|
483
|
+
message = f"{METHOD}[{entry_id}]: {summary}; running"
|
|
484
|
+
if check_trouble and not trouble:
|
|
485
|
+
message += (
|
|
486
|
+
"; the core check reported halt/reset trouble (" + ", ".join(check_trouble) + ")"
|
|
487
|
+
)
|
|
488
|
+
if trouble:
|
|
489
|
+
message += (
|
|
490
|
+
"; the load only worked through a J-Link fallback (" + ", ".join(trouble) + ") -- "
|
|
491
|
+
"the core did not halt/reset cleanly, so power-cycle before trusting this run"
|
|
492
|
+
)
|
|
493
|
+
if ctx.ram_console:
|
|
494
|
+
if console is None:
|
|
495
|
+
message += (
|
|
496
|
+
f"; no {CONSOLE_SYMBOL} symbol -- this build selected the UART console "
|
|
497
|
+
"(read it on the console, e.g. `tan monitor`); nothing to read over SWD"
|
|
498
|
+
)
|
|
499
|
+
else:
|
|
500
|
+
if not watches and not hold: # a watch/hold session already ran the whole --wait window
|
|
501
|
+
time.sleep(max(ctx.ram_wait, 0.0))
|
|
502
|
+
read = fc._execute(
|
|
503
|
+
FlashPlan(argv=argv, ok_message="", jlink_script=read_script(pre, *console)),
|
|
504
|
+
True, ctx.venv_bin, ctx.workspace, guard, jlink_exe=exe,
|
|
505
|
+
)
|
|
506
|
+
if guard is not None and guard.tripped:
|
|
507
|
+
return fail(guard.tripped, None, probe_refusal=guard.tripped_code)
|
|
508
|
+
bad = None if read.success else (fc._capture_tail(read) or "J-Link failed")
|
|
509
|
+
bad = bad or check_session(f"{read.stdout}\n{read.stderr}", loadbin=False)
|
|
510
|
+
if bad:
|
|
511
|
+
return fail(f"the image is running but the RAM console read failed: {bad}")
|
|
512
|
+
try:
|
|
513
|
+
data = read_back(f"{read.stdout}\n{read.stderr}", console[0], console[1])
|
|
514
|
+
except RamRunError as err:
|
|
515
|
+
return fail(f"the image is running but {err}")
|
|
516
|
+
text = decode_console(data)
|
|
517
|
+
ram_console.update(
|
|
518
|
+
{"bytesRead": len(data), "textBytes": len(text.encode()), "text": text}
|
|
519
|
+
)
|
|
520
|
+
message += f"; read {len(data)} B of {CONSOLE_SYMBOL} ({len(text)} chars)"
|
|
521
|
+
lines.append(f" ok: {message}")
|
|
522
|
+
return (
|
|
523
|
+
0,
|
|
524
|
+
entry("ok", 0, message, preflight_unarmed=unarmed,
|
|
525
|
+
reset_unconfirmed=bool(trouble or check_trouble), trcena_note=True, trcena_hold=hold,
|
|
526
|
+
ram_watch_incomplete=watch_note, **warn_missing),
|
|
527
|
+
lines,
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def _load_apertures(ctx: Any, core_id: str) -> Any:
|
|
532
|
+
"""The core's code/data apertures from the SoC metadata of the SDK in use
|
|
533
|
+
(`sram_banks_kb` of the manifest SKU's silicon variant). Refuses -- never guesses a
|
|
534
|
+
size -- when the SDK metadata, the SoM preset or the variant's banks cannot be
|
|
535
|
+
read."""
|
|
536
|
+
from tan.commands.build_output import read_sdk_som_and_soc
|
|
537
|
+
from tan.core.size import resolve_variant, sram_banks
|
|
538
|
+
|
|
539
|
+
metadata_root = os.path.join(ctx.sdk_root, "metadata") if ctx.sdk_root else None
|
|
540
|
+
why: list[str] = []
|
|
541
|
+
walked = (
|
|
542
|
+
read_sdk_som_and_soc(metadata_root, ctx.sku, skipped=why, explain_unsupported=True)
|
|
543
|
+
if metadata_root and ctx.sku and os.path.isdir(metadata_root)
|
|
544
|
+
else None
|
|
545
|
+
)
|
|
546
|
+
if walked is None:
|
|
547
|
+
raise RamRunError(
|
|
548
|
+
f"cannot bound the image: no readable SoM preset / SoC metadata for "
|
|
549
|
+
f"'{ctx.sku}' under {metadata_root}"
|
|
550
|
+
+ (f" ({'; '.join(why)})" if why else "")
|
|
551
|
+
+ " -- refusing to guess the TCM sizes"
|
|
552
|
+
)
|
|
553
|
+
_silicon, silicon_variant, variants, _flash_mb, _cores = walked
|
|
554
|
+
variant = resolve_variant(silicon_variant, ctx.sku, variants)
|
|
555
|
+
apertures = apertures_for(core_id, sram_banks(variant)) if variant else None
|
|
556
|
+
if apertures is None:
|
|
557
|
+
raise RamRunError(
|
|
558
|
+
f"cannot bound the image: the SoC variant for '{ctx.sku}' lists no "
|
|
559
|
+
f"ITCM/DTCM bank for core '{core_id}' -- refusing to guess the TCM sizes"
|
|
560
|
+
)
|
|
561
|
+
return apertures
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _save_transcript(ctx: Any, entry_id: str, report: dict[str, Any], script: str, outcome: Any) -> None:
|
|
565
|
+
safe = re.sub(r"[^A-Za-z0-9._-]", "_", entry_id) or "entry"
|
|
566
|
+
stamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
|
|
567
|
+
path = os.path.join(ctx.build_root, "flash-logs", f"{METHOD}-{safe}-{stamp}.log")
|
|
568
|
+
try:
|
|
569
|
+
report["jlink"]["transcriptPath"] = fc._write_transcript(
|
|
570
|
+
path,
|
|
571
|
+
f"# tan flash --ram [{entry_id}] rc={outcome.returncode}\n## script\n"
|
|
572
|
+
f"{fc._DISABLE_FW_UPDATE}{script}\n## stdout\n{outcome.stdout}\n## stderr\n"
|
|
573
|
+
f"{outcome.stderr}\n",
|
|
574
|
+
)
|
|
575
|
+
except OSError as err:
|
|
576
|
+
report["jlink"]["transcriptPath"] = None
|
|
577
|
+
report["jlink"]["transcriptError"] = str(err)
|
|
578
|
+
report["jlink"]["transcriptTail"] = fc.transcript_tail(f"{outcome.stdout}\n{outcome.stderr}")
|