MESA¶
MESA (Manifest driven Example System for All-platforms) is the runtime
helper that every shipped ChipScoPy example notebook uses to locate its
programming and probes files, validate that the connected device matches
the expected design, and program the device with the correct flow
(flat or segmented).
Each design ships with a manifest.json that captures the platform’s
debug cores, programming flow, and supported example IDs. MESA discovers
those manifests, resolves any extends chain, and exposes a small
typed Python API. Users write one notebook; MESA adapts it to whichever
hardware platform the manifest targets.
Quick start¶
Every notebook in chipscopy/examples/ uses the same setup-cell shape,
built around resolve_example_design(). It returns an
ExampleDesign that hides whether the notebook is running in
MESA mode (manifest-driven) or direct mode (user-supplied PDI /
LTX), so the rest of the example is identical in both cases.
import os
from chipscopy import create_session, delete_session
from chipscopy.examples.mesa import resolve_example_design
CS_URL = os.getenv("CS_SERVER_URL", "TCP:localhost:3042")
HW_URL = os.getenv("HW_SERVER_URL", "TCP:localhost:3121")
HW_PLATFORM = "vck190"
EXAMPLE_ID = "ila_and_vio"
PROGRAMMING_FILE = "" # Direct mode: set to your own PDI to skip MESA
PROBES_FILE = ""
example_design = resolve_example_design(
HW_PLATFORM,
EXAMPLE_ID,
programming_file=PROGRAMMING_FILE,
probes_file=PROBES_FILE,
)
example_design.print_summary()
session = create_session(cs_server_url=CS_URL, hw_server_url=HW_URL)
device = session.devices.filter_by(family=example_design.device_family).get()
if not example_design.verify_device_idcode(device):
raise RuntimeError("Device IDCODE does not match the manifest design.")
example_design.program_device(device)
device.discover_and_setup_cores(ltx_file=example_design.probes_file)
# ... your example logic here ...
delete_session(session)
The HW_PLATFORM and EXAMPLE_ID constants are the only things a
notebook author needs to set; everything else is derived from the
manifest.
ExampleDesign paths (flat vs segmented)¶
ExampleDesign exposes string fields programming_file and
probes_file for the usual notebook pattern (assign to PROGRAMMING_FILE
/ PROBES_FILE and pass them to APIs such as
device.discover_and_setup_cores(ltx_file=...)). It also exposes
programming_files and probes_files: ordered lists of resolved
programming paths and any matching LTX paths. probes_files may be empty
or shorter than programming_files when no LTX is present (LTX is for
debug setup, not for device.program).
For programming_flow: "flat", each list has at most one element matching
the scalar fields when paths exist. For "segmented", programming_files
is [boot, PLD] in that order; the scalars are set to the PLD pair when
an LTX is resolved so ILA/VIO and other PL-side debug use the correct LTX
without per-notebook branching. If no segmented LTX is found, probes_file
falls back to any LTX returned by chipscopy.get_design_files(), or is
empty. Boot and PLD PDIs are always required for segmented programming; LTX
files are optional and are resolved with the same manifest glob patterns when
present.
To retarget another board, change HW_PLATFORM (or override it via
the environment) - any platform that has a manifest will work:
HW_PLATFORM=vck190 python my_example.py
HW_PLATFORM=vpk120 python my_example.py
HW_PLATFORM=vcu128 python my_example.py
Working with the manifest¶
The ExampleDesign.manifest attribute returns a typed
Manifest (or None in direct mode). Use it to gate
optional capabilities cleanly instead of hard-coding per-platform
branches in the notebook.
manifest = example_design.manifest
if manifest and manifest.has_core("memory"):
memory = device.memory[0]
if manifest and manifest.has_all_cores("ila", "vio"):
ila = device.ila_cores[0]
if manifest and manifest.has_feature("memory", "2d_eye_scan"):
run_2d_eye_scan(device)
For platform-specific knobs (quad names, ILA instance paths, NoC node
names), use Manifest.get_core_config() so the notebook reads the
value from the manifest rather than embedding it in code:
quad_names = manifest.get_core_config("ibert_gty", "quad_names", [])
node_names = manifest.get_core_config("noc_perfmon", "node_names", [])
ila_instance = manifest.get_core_instance("ila", index=0)
if ila_instance:
ila_name = ila_instance["name"]
probe_prefix = ila_instance.get("probe_prefix", "")
Manifest structure¶
Each design directory under examples/designs/<platform>/<design>
contains a manifest.json like this:
{
"extends": "_base/versal_standard_cores.json",
"design_info": {
"design_name": "chipscopy_ced",
"description": "ChipScoPy CED for VCK190",
"hw_platform": "vck190",
"programming_flow": "flat",
"design_path": "vck190/production/chipscopy_ced",
"family": "versal",
"device": "xcvc1902",
"board": "VCK190",
"idcode": "0x14CA8093"
},
"debug_cores": {
"ibert_gty": {
"enabled": true,
"quad_names": ["Quad_205", "Quad_204", "Quad_201", "Quad_105"]
}
},
"supported_examples": [
"ila_and_vio",
"link_and_eye_scan",
"ddr_example"
],
"metadata": {
"version": "1.0.0",
"maintainer": "AMD ChipScoPy Team"
}
}
Notable fields:
extends(optional) - relative path to a base manifest under_base/; child manifests deep-merge over the base.programming_flow- must be"flat"(single PDI) or"segmented"(boot + PLD PDI for partial reconfiguration).family- must match a ChipScoPy device family (versal,virtexuplus, etc.).idcode/idcode_list- JTAG IDCODE(s) used byExampleDesign.verify_device_idcode()to detect the wrong board before programming. Useidcode_listfor multi-variant silicon (e.g. production + ES).
The full schema lives in
chipscopy/examples/mesa/manifest_schema.json. Both the JSON schema
and the Python-side ManifestValidator set
additionalProperties: false for nested debug_cores entries, so
typo’d keys (e.g. descripton) are rejected at validation time
instead of silently behaving as no-ops at runtime.
Programming flows¶
ExampleDesign.program_device() and Manifest.program_device()
both dispatch on the manifest’s programming_flow field through an
internal flow table; adding a new flow is a one-line registration.
Flow |
PDI files |
Skip reset |
Use case |
|---|---|---|---|
|
1 (monolithic) |
No |
Simple designs, full configuration |
|
2 (boot + PLD) |
Yes (PLD) |
Partial reconfiguration, boot + dynamic |
Segmented boot and PLD PDIs (and LTX paths during example resolution) use
the manifest’s boot_pdi_pattern / pld_pdi_pattern with the same
matching rules whenever MESA resolves files or runs the segmented program
steps.
Management CLI (internal)¶
ChipScoPy maintainers use the private chipscopy.examples.mesa._cli
module to validate, lint, and scaffold MESA manifests and example notebooks.
End users do not need to call it; it is documented here as a reference for
maintainers contributing new MESA examples.
# Validate every manifest under chipscopy/examples/designs.
python -m chipscopy.examples.mesa._cli validate --all
# Validate a specific manifest by path.
python -m chipscopy.examples.mesa._cli validate --manifest path/to/manifest.json
# Cross-check manifests vs. notebook filenames; flag dangling references
# and per-manifest lint warnings.
python -m chipscopy.examples.mesa._cli lint
# Add an example ID to all compatible manifests (use --dry-run first).
python -m chipscopy.examples.mesa._cli add-example \
--example-id my_example --dry-run
# Scaffold a new MESA-powered example notebook.
python -m chipscopy.examples.mesa._cli new-example \
--example-id my_example --template basic
# Print a compatibility report (platforms, examples, categories).
python -m chipscopy.examples.mesa._cli report
API reference¶
Notebook entry points¶
- chipscopy.examples.mesa.resolve_example_design(hw_platform, example_id, *, programming_file='', probes_file='', device_family='versal')[source]¶
Resolve programming and probes files for an example notebook.
Two paths are supported, in this order:
Direct mode: if
programming_fileis non-empty the MESA manifest lookup is skipped entirely. The notebook can run with any user-provided PDI/LTX combination - no manifest is required.MESA mode: otherwise the design is resolved from the MESA manifest for
hw_platformandexample_id. The platform’sdesign_pathis converted into actual file paths viachipscopy.get_design_files(), anddevice_familyis taken from the manifest.
- Raises:
RuntimeError – In MESA mode when no compatible manifest is found.
- Return type:
- chipscopy.examples.mesa.get_manifest(platform, example_id=None)[source]¶
Get MESA manifest for platform and optional example ID.
- Return type:
Optional[Manifest,None]
- chipscopy.examples.mesa.get_all_platforms()[source]¶
Get list of all available platforms.
- Return type:
List[str]
- chipscopy.examples.mesa.get_designs_directory()[source]¶
Return the MESA designs directory.
Single source of truth for
examples/designs/lookup. Honours theCHIPSCOPY_EXAMPLESenvironment variable throughchipscopy.get_examples_dir_or_die()so notebooks, the registry and CLI all agree on the same location.- Return type:
Path
ExampleDesign¶
- class chipscopy.examples.mesa.ExampleDesign(manifest, design_files, programming_file, probes_file, device_family, hw_platform, example_id, programming_files=<factory>, probes_files=<factory>)[source]¶
Resolved design files for an example notebook.
Hides whether the notebook is running in MESA mode (manifest-driven) or direct mode (user-supplied PDI/LTX), so the rest of the notebook uses one consistent interface.
- manifest¶
Loaded
Manifestwhen MESA resolved the design, orNonewhen the user supplied design files directly.- Type:
- design_files¶
DesignFilesobject fromchipscopy.get_design_files()when MESA is used,Noneotherwise.- Type:
Any | None
- programming_file¶
Path to the PDI / programming file used by the device.
- Type:
str
- probes_file¶
Path to the LTX / probes file used by the device.
- Type:
str
- device_family¶
Device family string suitable for
session.devices.filter_by(family=...).- Type:
str
- hw_platform¶
Hardware platform identifier (e.g.
"vck190").- Type:
str
- example_id¶
Example ID requested by the notebook.
- Type:
str
- programming_files¶
Ordered programming file paths (boot then PLD when segmented).
- Type:
List[str]
- probes_files¶
Ordered LTX paths when resolved (boot then PLD when both exist). May be shorter than
programming_filesor empty when no LTX is available; probe files are optional and not required forprogram_device().- Type:
List[str]
- print_summary()[source]¶
Print the server-independent design details used by the notebook.
- Return type:
None
- program_device(device, **program_options)[source]¶
Program the device using the resolved design files.
In MESA mode this delegates to
Manifest.program_device(), which handles flat vs. segmented programming flows. In direct mode it falls back todevice.program(self.programming_file).- Return type:
None
- property using_manifest: bool¶
True when this design was resolved through a MESA manifest.
- Return type:
bool
- verify_device_idcode(device)[source]¶
Verify the device JTAG IDCODE matches the resolved design.
Returns
Truein direct mode (no manifest constraint) and delegates toManifest.verify_device_idcode()in MESA mode.- Return type:
bool
Manifest¶
- class chipscopy.examples.mesa.Manifest(design_info, debug_cores, supported_examples, metadata, manifest_path)[source]¶
Type-safe MESA manifest representation.
Provides IDE autocomplete and type checking for manifest fields.
- classmethod from_dict(data, manifest_path)[source]¶
Create Manifest from a dictionary that has already been merged with its bases.
- Return type:
- classmethod from_file(path)[source]¶
Load and return a Manifest from
path, resolving anyextendschain.Raises
ManifestErrorfor any load / parse / merge / required-field problem so callers can catch a single exception type.- Return type:
- get_all_enabled_cores_by_prefix(prefix, filter_fn=None)[source]¶
Get all enabled cores whose name starts with
prefix(with optional filter).- Return type:
List[Tuple[str,DebugCore]]
- get_all_ibert_cores(filter_fn=None)[source]¶
Get all enabled IBERT cores with optional filtering.
- Return type:
List[Tuple[str,DebugCore]]
- get_core_config(core_name, config_key, default=None)[source]¶
Get a platform-specific configuration value from a debug core.
For platform-specific hardware details like quad names, node names, and core instances. Algorithm parameters (scan patterns, step sizes, thresholds) should remain visible in notebooks for learning.
- get_core_instance(core_name, index=0)[source]¶
Get a specific core instance by name and index.
Thin wrapper around
get_core_config()that returns the entry from the core’score_instanceslist atindex.- Return type:
Optional[Dict,None]
- get_first_enabled_core_by_prefix(prefix, filter_fn=None, index=0)[source]¶
Get enabled core by prefix with optional filtering and indexing.
- Parameters:
prefix (
str) – Core name prefix to match (e.g.,"ibert_","ila","vio").filter_fn (
Optional[Callable[[str,DebugCore],bool],None]) – Optional(core_name, core) -> boolfor custom filtering.index (
int) – Index of matching core to return (default0).
- Return type:
Optional[Tuple[str,DebugCore],None]- Returns:
Tuple of
(core_name, DebugCore)orNone.
- get_ibert_core(filter_fn=None, index=0)[source]¶
Get IBERT core (any type) with optional custom filtering and indexing.
- Return type:
Optional[Tuple[str,DebugCore],None]
- static get_mem_type_name(mem_type_val)[source]¶
Translate DDR memory type integer code to human-readable name.
- Parameters:
mem_type_val (
int) – Integer fromddr_node.get_property(["mem_type"])["mem_type"].- Return type:
str- Returns:
String name like
"DDR4","LPDDR4","DDR5","LPDDR5", or"Unknown(N)".
- has_all_cores(*core_names)[source]¶
Check if all specified cores are present and enabled.
- Return type:
bool
- has_feature(core_name, feature)[source]¶
Check if a specific feature is available for a core.
- Return type:
bool
- program_device(device, design_files, *, delay_after_program=0, show_progress_bar=True, progress=None, done=None)[source]¶
Program
deviceaccording to the manifest’s programming flow.Dispatches to the appropriate flow handler based on
design_info.programming_flow. Adding a new flow is one entry in_FLOW_HANDLERS.- Return type:
None
- supports_example(example_id)[source]¶
Check if this manifest supports a specific example.
- Return type:
bool
- verify_device_idcode(device)[source]¶
Verify device JTAG IDCODE matches manifest expectation.
Returns
Trueif no IDCODE constraint is specified, if all IDCODEs are placeholders, or if the device IDCODE matches any configured value. ReturnsFalseonly when a real IDCODE is specified and the device does not match.- Return type:
bool
- class chipscopy.examples.mesa.DebugCore(enabled, description, features=<factory>, quad_names=None, memory_types=None, core_instances=None, node_names=None, trigger_base_address=None, probe_mapping=None, vio_hierarchy=None)[source]¶
Represents a debug core configuration.
Registry and errors¶
- class chipscopy.examples.mesa.ManifestRegistry[source]¶
MESA manifest registry for design discovery.
Manifests are loaded lazily and cached by file path. Each cached entry is keyed on the file’s mtime so notebook reruns automatically pick up edits without an explicit invalidate call.
- find_manifest_files()[source]¶
Find all manifest.json files under the configured designs directory.
- Return type:
List[Path]
- get_all_platforms()[source]¶
Get sorted list of all available platforms across all manifests.
- Return type:
List[str]
- get_designs_directory()[source]¶
Get the designs directory path (delegates to
get_designs_directory()).- Return type:
Path
- get_manifest(platform, example_id=None)[source]¶
Get MESA manifest for
platformand optionalexample_id.Returns the first manifest whose
hw_platformmatches and that either supports the requested example or - if no example is given - is just the first match. ReturnsNonewhen no manifest matches.- Return type:
Optional[Manifest,None]
- invalidate_cache(platform=None)[source]¶
Drop cached manifests. Filters by platform when one is given.
- Return type:
None
- invalidate_directory_cache()[source]¶
Backward-compatible alias for
invalidate_cache().- Return type:
None
Validation¶
- chipscopy.examples.mesa.validate_manifest_file(filepath)[source]¶
Validate a manifest file (resolving any
extendschain first).Returns
(is_valid, errors). Inheritance is resolved exactly as it will be at runtime so override-only typos are caught here.- Return type:
Tuple[bool,List[str]]
- class chipscopy.examples.mesa.ManifestValidationReporter[source]¶
CLI-friendly reporter that wraps
validate_manifest_file().Adds non-schema lint warnings (missing recommended
description/maintainerfields, emptysupported_examples) on the fully merged manifest and formats the result for terminal output. All authoritative schema rules still live inManifestValidator; this class only layers CLI presentation on top.