Skip to content

Platform#

The silicon-info lookups: per-SoC capability tables, boards, and the registry that resolves them (including user custom_socs/custom_boards overlays). This surface is experimental: it is the seed of a future shared silicon-info package, so shapes may still move.

get_soc #

get_soc(name: str, *, registry: PlatformRegistry | None = None) -> SocDef

Look up a SoC definition by name.

SocDef dataclass #

SocDef(name: str, family: SocFamily, core: CoreArch, pmu_tier: PmuTier, has_mve: bool, memory: MemoryLayout, clocks: tuple[ClockDomain, ...], c_define: str, cmsis_header: str, rtt_scan_ranges: tuple[tuple[int, int], ...], jlink_device: str = '', pmu_max_ops: int = 2048, swo_trace_clock_mhz: int | None = None, has_usb: bool = True, ssram_full_power_enum: str = 'AM_HAL_PWRCTRL_SRAM_3M', has_radio_subsystem: bool = False, app_flash_load_addr: int | None = None, origin: SocOrigin = CUSTOM, registered_name: str | None = None)

Definition of an Ambiq SoC relevant to profiling.

is_builtin property #

is_builtin: bool

Whether the name-keyed built-in tables may speak for this part.

Both halves are load-bearing, and each covers a hole the other leaves:

  • :attr:origin alone is too loose. It survives dataclasses.replace by design -- that is the point, see :class:SocOrigin -- but so does a replace that changes the name, which is the obvious way to build a custom SocDef from a built-in programmatically. Nothing documents that path -- docs/guide/boards.md shows a fresh SocDef(...) constructor instead, which defaults to CUSTOM/None and is safe -- but a caller reaching for replace unprompted is precisely the case a default-safe field cannot catch. replace(get_soc("apollo510"), name="atomiq110") would otherwise keep BUILTIN and read atomiq110's per-SoC override -- an address belonging to a different part, which is the df34b6e forgery reopened one dimension over.
  • An is _SOCS[name] identity check alone is too strict, and was the bug origin replaced: get_soc_for_board returns a replace copy whenever the board overrides psram_kb (7 built-in boards do), and identity silently reclassifies those as unknown parts.

Requiring the stamped name to still match :attr:name accepts every copy that is still describing the part it was registered as, and rejects every copy that has been renamed into another part's shoes.

cpu_clock property #

cpu_clock: ClockDomain

The CPU clock domain (every SoC declares one).

capabilities property #

capabilities: SocCapabilities

Typed capability records resolved for this SoC.

All SoC-family policy is expressed once, here (via :func:~helia_profiler.platform.capabilities.build_soc_capabilities), so consumers read a named field instead of branching on family.

requires_attached_probe_for_cycles property #

requires_attached_probe_for_cycles: bool

Whether DWT cycle counts require a debugger attached during capture.

On the Cortex-M4F families (Apollo3/3P and Apollo4/4P/4L) the DWT->CYCCNT counter lives in the core debug power domain, which stays powered only while a debugger asserts the DAP's CDBGPWRUPREQ — a signal firmware cannot set from the core. The SWO/RTT readers keep a debugger attached incidentally, but the UART/USB readers release the probe, so per-layer cycles read back as 0. When this is True those readers must hold a pylink session open for the whole capture (see attached_reset_session). AP3 gating was confirmed empirically (2026-06-27): AOT-over-UART read 0 cycles until the probe was held attached, after which it matched the RTT/SWO cycle counts. AP5 (Cortex-M55) uses the resettable Armv8-M PMU and its secure bootloader prefers the probe released, so it stays False.

profiling_backends property #

profiling_backends: tuple[str, ...]

Concrete profiling backends available on this SoC.

This is intentionally more explicit than pmu_tier so callers do not flatten a CM55 target into a single boolean like has_full_pmu.

profiling_domains property #

profiling_domains: tuple[str, ...]

High-level compute domains the profiler can target on this SoC.

clock_domain #

clock_domain(name: str) -> ClockDomain | None

Return the named clock domain, or None if not present.

build_platform_registry #

build_platform_registry(*, base: PlatformRegistry | None = None, socs: Mapping[str, SocDef] | None = None, boards: Mapping[str, BoardDef] | None = None) -> PlatformRegistry

Return a frozen platform registry for one config/run.