Export solved configurations to pyadi-dt
pyadi-jif can export a solved system as the versioned adi.jif-dt contract.
The contract contains solved electrical intent—JESD links, semantic clock
requirements, rates, dividers, and FPGA settings—but deliberately excludes
physical clock output channels and device-tree labels.
pyadi-dt owns that physical placement and joins each semantic ID to a board profile before generating or modifying a device tree. This prevents requested clock order inside the solver from being mistaken for HMC7044 or AD952x output channel numbering.
Solve and export an AD9680 system
The complete runnable example is checked by the normal example test suite:
"""Solve AD9680 clocks and export the versioned pyadi-jif -> pyadi-dt contract."""
import adijif
system = adijif.system("ad9680", "hmc7044", "xilinx", 125_000_000)
system.converter.sample_clock = 1_000_000_000
system.converter.decimation = 1
system.converter.set_quick_configuration_mode(str(0x88))
system.converter.K = 32
system.fpga.setup_by_dev_kit_name("zc706")
system.fpga.force_qpll = 1
solution = system.solve()
contract = system.export_config(format="adi.jif-dt", solution=solution)
# The JSON contains semantic requirements only. A pyadi-dt board profile maps
# them onto physical output channels and device-tree labels.
print(contract.to_json(), end="")
Run it directly or redirect the portable result to a file:
python examples/ad9680_jif_dt_contract.py > ad9680.jif-dt.json
The important API boundary is:
solution = system.solve()
contract = system.export_config(format="adi.jif-dt", solution=solution)
contract.to_json_file("ad9680.jif-dt.json")
Passing the existing solution avoids solving twice. If it is omitted,
export_config() solves the current system first.
What the producer emits
For the AD9680 example, the contract contains one ad9680.rx link and four
semantic clock requirements:
ad9680.device-clockad9680.sysrefad9680.fpga-refad9680.fpga-link
Each clock has a solved rate and divider, but no output_index or dt_label.
Those values depend on the carrier and FPGA design, not the solver.
The output begins with:
{
"clock_requirements": [
{
"divider": 3,
"id": "ad9680.device-clock",
"rate_hz": 1000000000,
"role": "converter-device",
"sink": "AD9680",
"source": "HMC7044"
}
],
"producer": {
"name": "pyadi-jif",
"version": "0.1.6"
},
"schema": "adi.jif-dt",
"version": "1.0"
}
Consumer-side binding
pyadi-dt loads the JSON with its strict JifDtContract projection, then uses a
separate JifDtBindings object to map semantic requirements to physical clock
channels and XSA/device-tree labels. See the
pyadi-dt interface contract documentation
for binding examples, validation order, and compatibility rules.
The producer and consumer both enforce contract version 1.0. Unsupported versions, inconsistent JESD transport/lane rates, duplicate IDs, fractional hertz, and non-JSON solver objects fail before a device tree can be changed.
Current topology support
system.export_config() initially supports one non-nested ADC or DAC converter.
Nested transceivers and MxFE systems require an explicit follow-up extension so
their multiple links retain stable identities rather than relying on computed
dictionary key parsing.