PyRogue Device Tree

The application’s PyRogue device tree mirrors the AXI-Lite crossbar hierarchy in RTL. Each pr.Device carries an offset relative to its parent. The values below are sourced from firmware/python/simple_zcu216_example/_Root.py, firmware/python/simple_zcu216_example/_RFSoC.py, and firmware/python/simple_zcu216_example/_Application.py.

Hierarchy

The ZCU216 design uses 16 ADC channels and 16 DAC channels. The Application device declares its children with offset values that match the RTL Application crossbar (see Application Register Map):

self.add(rfsoc_utility.AppRingBuffer(
    offset   = 0x00_000000,
    numAdcCh = 16, # Must match NUM_ADC_CH_G config
    numDacCh = 16, # Must match NUM_DAC_CH_G config
))

self.add(rfsoc_utility.SigGen(
    name         = 'DacSigGen',
    offset       = 0x01_000000,
    numCh        = 16,  # Must match NUM_CH_G config
    ramWidth     = 10, # Must match RAM_ADDR_WIDTH_G config
    smplPerCycle = 16, # Must match SAMPLE_PER_CYCLE_G config
))

The smplPerCycle = 16 parameter mirrors the RTL SAMPLE_PER_CYCLE_C constant declared in AppPkg Constants.

Startup sequence

Root.start() (in firmware/python/simple_zcu216_example/_Root.py) executes the following ordered sequence after the base pr.Root.start() runs:

  1. TCP connection setup (memory map + RFDC + ring-buffer streams).

  2. Stream wiring (ADC/DAC ring buffer paths chained to DataWriter and to per-channel host-side processors via >>).

  3. User-logic reset (RFSoC.AxiSocCore.UserRst()).

  4. LMK clock chip initialization (Hardware.InitClock).

  5. DSP-clock-stable wait (RFSoC.AxiSocCore.DspRstWait()).

  6. Application enable (RFSoC.Application.enable.set(True)) — only after the DSP clock is stable.

  7. RFDC initialization and MTS sync (Rfdc.Init() and Rfdc.Mts.*).

  8. Default YAML configuration load (LoadConfig).

  9. DacSigGen waveform load (CSV file or LoadSingleTones fallback).

The Application device is constructed with enabled=False and is deliberately enabled only after step 5. Bypassing this order leaves the application reading registers in an unknown clock state.

For platform-level PyRogue patterns — the AxiSocCore interface, the Rfdc API, and the host-side RingBufferProcessor stream pipeline — see reference/pyrogue_api.html.

Public package surface

The simple_zcu216_example package exposes its public classes via a wildcard re-export pattern in firmware/python/simple_zcu216_example/__init__.py:

from simple_zcu216_example._Application import *
from simple_zcu216_example._RFSoC       import *
from simple_zcu216_example._Root        import *

Private implementation files are underscore-prefixed (_Application.py, _RFSoC.py, _Root.py); __init__.py is the public face.