SoC Zynq — PS + PL Integration
Understanding the Zynq architecture: the processor (PS) and FPGA (PL) sides, their AXI communication, and designing a complete embedded system.
What is a SoC?
A SoC (System on Chip) integrates onto a single die:
- One or more processors (ARM, RISC-V…)
- Programmable logic (FPGA)
- Peripherals (memory, USB, Ethernet, UART…)
AMD/Xilinx's Zynq-7000 family is one of the most popular in the industry. It combines a dual-core ARM Cortex-A9 and an FPGA fabric on the same silicon.
Zynq-7000 architecture: PS (ARM Cortex-A9 + peripherals) connected to PL (FPGA) via AXI interfaces
Image à ajouter
The Two Sides of Zynq
Processing System (PS)
The PS side is the software world:
| Element | Detail |
|---|---|
| CPU | Dual-core ARM Cortex-A9 (up to 866 MHz) |
| Cache | L1 (32 KB) + L2 (512 KB) |
| RAM | DDR3/DDR2/LPDDR2 (external connection) |
| Peripherals | USB, Ethernet, UART, SPI, I2C, GPIO |
| OS | Bare-metal, FreeRTOS, Linux |
The PS can operate independently of the FPGA side — it boots from its Flash or SD card.
Programmable Logic (PL)
The PL side is the classic FPGA fabric:
- LUTs, flip-flops, BRAMs, DSPs
- All your VHDL runs here
- Can be reprogrammed at runtime (partially)
- Typical clock rates: 100–300 MHz
PS ↔ PL Communication
The PS and PL communicate via AXI interfaces:
| Interface | Direction | Use |
|---|---|---|
| AXI HP (High Performance) | PS ↔ PL | High-speed DMA transfers to RAM |
| AXI GP (General Purpose) | PS → PL | CPU access to PL registers |
| AXI ACP (Accelerator Coherency Port) | PL → PS | Cache-coherent access |
| EMIO | PS ↔ PL | GPIO, SPI, I2C extension through PL |
AXI interfaces between PS and PL: AXI_GP (register access CPU→PL), AXI_HP (DMA PL→DDR), EMIO (extended GPIO)
Image à ajouter
Creating a SoC Project in Vivado
Step 1 — New Vivado Project
Create an RTL project and select your Zynq board (PYNQ-Z2, ZedBoard, Cora Z7…).
Vivado: project creation with PYNQ-Z2 board selected
Image à ajouter
Step 2 — Create the Block Design
In the left panel: IP Integrator → Create Block Design.
Vivado: Create Block Design menu in IP Integrator
Image à ajouter
Step 3 — Add the Processing System
Right-click in the canvas → Add IP → search for "Zynq7 Processing System".
Vivado Block Design: adding the ZYNQ7 Processing System block
Image à ajouter
Click "Run Block Automation" to automatically apply your board's constraints (DDR presets, clock…).
Vivado: Run Block Automation applies PYNQ-Z2 board presets
Image à ajouter
Step 4 — Configure the PS
Double-click the PS block to open its configuration:
- PS-PL Configuration: enable the required AXI interfaces (GP0, HP0…)
- Clock Configuration: set the PL clock frequency (100 MHz by default)
- MIO Configuration: choose which PS peripherals to enable (UART, USB…)
Vivado: PS Zynq configuration window — PS-PL Configuration tab with AXI GP0 enabled
Image à ajouter
Step 5 — Add Your VHDL IP
To connect your VHDL to the PS, you wrap it in an IP with an AXI-Lite interface:
- Tools → Create and Package New IP
- Choose "AXI-Lite Slave" as the interface
- Define the AXI registers (read/write)
- Add your VHDL logic to the generated file
Vivado: Create and Package New IP wizard — AXI4-Lite interface selection
Image à ajouter
Step 6 — Connect the Blocks
After adding your IP to the block design:
- Right-click → Add IP and search for your custom IP
- Click "Run Connection Automation" → Vivado wires the AXI Interconnect automatically
Complete Vivado Block Design: PS Zynq + AXI Interconnect + custom IP — AXI connections visible
Image à ajouter
Step 7 — Generate the Bitstream
- Validate Design (F6) to check connections
- Right-click the block design → Generate Output Products
- Right-click → Create HDL Wrapper
- Generate Bitstream
Vivado: Generate Bitstream in progress — implementation progress shown
Image à ajouter
Step 8 — Export to Vitis / SDK
- File → Export → Export Hardware (include bitstream)
- Open Vitis (or SDK for versions < 2020.1)
- Create a C/C++ bare-metal or Linux application
Vitis: creating a bare-metal C project on the exported Zynq platform
Image à ajouter
CPU ↔ FPGA Communication in Practice
Once deployed, the CPU accesses your VHDL registers via AXI-Lite:
// Bare-metal C — read/write PL registers
#include "xparameters.h"
#include "xil_io.h"
// Base address of your IP (defined by xparameters.h)
#define MY_IP_BASEADDR XPAR_MY_IP_0_BASEADDR
// Write to register 0 (offset 0x00)
Xil_Out32(MY_IP_BASEADDR + 0x00, 0xDEADBEEF);
// Read register 1 (offset 0x04)
uint32_t val = Xil_In32(MY_IP_BASEADDR + 0x04);On the VHDL side, your IP reads/writes these registers through the AXI-Lite signals generated by Vivado.
Comparison: Pure FPGA vs Zynq SoC
| Criterion | Pure FPGA | Zynq SoC |
|---|---|---|
| Processing | All in VHDL | CPU for soft, FPGA for acceleration |
| Flexibility | Very high | High (+ OS possible) |
| Debugging | Hardware signals | printf + hardware ILA |
| High-level interfaces | Coded in VHDL | USB, Ethernet, Linux native |
| Dev time | Long | Shorter for the soft side |
| Use case | Pure real-time processing | Hardware/software co-design |
Key Points to Remember
- Zynq separates PS (ARM, software) and PL (FPGA, hardware)
- PS ↔ PL communication goes through AXI interfaces
- Vivado Block Design is the tool for visually assembling blocks
- Your VHDL code becomes a packaged IP accessible from the CPU
- Full flow: VHDL → Package IP → Block Design → Bitstream → Vitis/SDK