Architecture Overview

This page describes the application-specific topology of Simple-ZCU208-Example on the Xilinx ZCU208 evaluation board (XCZU48DR-FSVG1517-2-E). It covers what is unique to this application: the 8-channel ADC capture path, the 8-channel DAC output path, the ring-buffer DMA model, the three local clock domains, and the startup discipline that ties RTL and PyRogue together.

For platform-level RFSoC architecture (clock-domain CDC philosophy, DMA platform model, AXI-Lite hierarchy in general), see explanation/architecture.html.

Topology

The application is built around the Xilinx RFDC IP wrapped by RfDataConverter, an AppRingBuffer block for capture and loopback, and a RAM-based SigGen for DAC waveforms. Data movement is split across two DMA lanes:

  • 8-channel ADC capture path: RFDC -> AppRingBuffer -> DMA lane 0 -> host TCP stream. Per-channel ring buffers are armed, triggered, and read back via PyRogue.

  • 8-channel DAC output path: DAC waveform RAM in SigGen -> RFDC -> physical DAC pins. Loopback samples are also captured back into AppRingBuffer for closed-loop debug.

  • Ring-buffer DMA model with DMA_SIZE_C = 2: lane 0 carries the ADC and DAC ring-buffer data; lane 1 is hard-wired loopback for debug. See AppPkg Constants for the constants and Top-Level RTL Entity for the entity surface.

Clock domains

Three asynchronous clock domains drive this application:

Clock

Frequency

Role

axilClk

100 MHz

Register access (PS-facing AXI-Lite); also drives the platform core’s auxClk / appClk inputs.

dspClk

312.5 MHz

DSP and DAC sample bus (Slv256Array, 16 samples per cycle, 8 channels ADC and 8 channels DAC).

adcClock

416.667 MHz

RFDC ADC output.

All three are declared as asynchronous clock groups in the XDC, so Vivado’s timing engine does not attempt to close timing across them. CDC crossings between any two domains use surf primitives (Synchronizer for control/status, Ssr12ToSsr16Gearbox for the ADC sample bus). For the platform-level CDC philosophy and the hub’s treatment of clock-group declarations, see explanation/architecture.html#clock-domains. Concrete signal names and the XDC excerpt live in Top-Level RTL Entity.

DMA model

The application uses two DMA lanes (DMA_SIZE_C = 2 in AppPkg Constants):

  • Lane 0 carries the ADC and DAC ring-buffer streams between the AppRingBuffer block and the host. The PyRogue Root wires this lane to per-channel RingBufferProcessor consumers and to the data-writer file sink.

  • Lane 1 is a hard-wired loopback used for DMA debug; the host pushes a frame down lane 1 and reads the same frame back, which exercises the DMA engine independently of the RFDC and ring-buffer logic.

Adding lanes is a coordinated change: DMA_SIZE_C in firmware/shared/rtl/AppPkg.vhd and the stream wiring in firmware/python/simple_zcu208_example/_Root.py must be updated together. For the platform-level DMA model (engine, AXI Stream framing, host TCP-bridge convention), see explanation/architecture.html#dma-model.

Sample bus

The parallel sample bus between RFDC and Application is a Slv256Array: 16 samples * 16 bits = 256 bits per channel per dspClk cycle. The SAMPLE_PER_CYCLE_C constant in AppPkg Constants ties the RTL generics (ADC_SAMPLE_PER_CYCLE_G, DAC_SAMPLE_PER_CYCLE_G, SAMPLE_PER_CYCLE_G) to the PyRogue smplPerCycle parameter. The 16-sample width is fixed for this application; changing it requires synchronized RTL and Python updates. The ZCU208 carries 8 ADC channels and 8 DAC channels on dspAdc / dspDac (each a Slv256Array(7 downto 0)). The PyRogue offsets and register addresses tied to this bus are documented in Application Register Map.

Startup discipline

The application’s PyRogue Application device is instantiated with enabled=False and is only enabled after the dspClk is stable. The Root.start() method enforces the order: user-logic reset, LMK clock chip initialization, DSP-reset wait, application enable, RFDC initialization, MTS sync, YAML config load, and finally the SigGen waveform load. Bypassing this sequence (for example, enabling Application before dspClk is running, or loading the SigGen waveform before MTS sync) is a known anti-pattern; registers that depend on dspClk will read back zero or DECERR.