00 Vivado Block Design iş akışı
Vivado Block Design (BD), IP bloklarını grafiksel olarak bağlamaya ve AXI Interconnect'i otomatik oluşturmaya olanak tanıyan entegre bir tasarım ortamıdır. Zynq SoC projeleri için temel araç akışıdır.
Yeni Zynq projesi oluşturma
Vivado → New Project → RTL Project
→ Part seçimi (örn. xc7z020clg484-1 ZedBoard)
→ IP Catalog açık tutulur
Create Block Design (BD):
IP Integrator → Create Block Design → "design_1"
→ Add IP → Zynq-7000 PS (ZYNQ7 Processing System)
→ Run Block Automation (PS MIO/DDR ayarları)
→ Add IP → (özel bloklarınız)
→ Run Connection Automation (AXI bağlantıları)
→ Validate Design
→ Generate Output Products
→ Create HDL Wrapper
Temel Vivado akış adımları
Vivado 2020.2+ sürümünden itibaren Tcl scriptleme tam destek görür. Tüm Block Design işlemleri Tcl ile otomatikleştirilebilir; bu sayede CI/CD pipeline entegrasyonu kolaylaşır.
Bu bölümde
- Block Design: grafiksel IP bağlama ortamı; AXI Interconnect otomatik üretilir
- Block/Connection Automation: PS yapılandırması ve AXI bağlantıları otomatik
- Address Editor: AXI slave adres atama — DTS ile uyumlu olmalı
- HDL Wrapper: BD'den sentez girişi; Tcl ile tam otomatik
01 IP Integrator ve Zynq PS yapılandırması
Zynq PS (ZYNQ7 Processing System) IP bloğu, PS'in MIO pinleri, DDR arayüzü, PLL saatleri ve PS-PL AXI portlarını yapılandırır. Bu adım her Zynq projesinin temelidir.
PS yapılandırma kategorileri
| Kategori | Ayarlar | Tipik değer |
|---|---|---|
| PS-PL Config | GP/HP port etkinleştirme, AXI geniş/dar | GP0 etkin, HP0 etkin (64-bit) |
| MIO Config | UART, I2C, SPI, USB, GigE, SD pin atamaları | UART1: MIO48/49, SD0: MIO40-45 |
| Clock Config | CPU_6x4x, DDR_3x2x, FCLK_CLK0–3 frekansları | CPU=667 MHz, FCLK0=100 MHz |
| DDR Config | DDR tipi, hız, genişlik, gecikme | DDR3, 533 MHz, 32-bit |
| Interrupts | IRQ_F2P etkinleştirme | 16 bit PL interrupt girişi |
FCLK — PL saat kaynağı
PS, PL'e 4 adet bağımsız saat çıkışı (FCLK_CLK0–3) sağlar. Her FCLK, PS PLL'inden türetilir ve 10–250 MHz arasında ayarlanabilir. AXI Interconnect ve özel IP'ler bu saatlerden beslenmelidir; birden fazla saat etki alanı kullanıldığında CDC (Clock Domain Crossing) tasarımı gerekir.
# Yeni Block Design oluştur
create_bd_design "design_1"
# Zynq PS IP ekle
create_bd_cell -type ip -vlnv xilinx.com:ip:processing_system7:5.5 ps7_0
# ZedBoard preset uygula
set_property -dict [list \
CONFIG.PCW_USE_S_AXI_HP0 {1} \
CONFIG.PCW_USE_M_AXI_GP0 {1} \
CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ {100} \
CONFIG.PCW_UART1_PERIPHERAL_ENABLE {1} \
CONFIG.PCW_UART1_UART1_IO {MIO 48 .. 49} \
CONFIG.PCW_SD0_PERIPHERAL_ENABLE {1} \
] [get_bd_cells ps7_0]
# PS saatini PL'e bağla
connect_bd_net [get_bd_pins ps7_0/FCLK_CLK0] \
[get_bd_pins ps7_0/M_AXI_GP0_ACLK]
Bu bölümde
- PS IP: MIO, DDR, PLL, GP/HP portları, IRQ_F2P — tek yapılandırma noktası
- FCLK0–3: PS'ten PL'e saat; 10–250 MHz arası ayarlanabilir
- Tcl ile tam otomatik yapılandırma — CI/CD için gerekli
02 AXI-Lite özel periferel — register haritası tasarımı
Vivado'nun "Create and Package New IP" sihirbazı, AXI-Lite slave şablonunu otomatik oluşturur. Bu şablona register haritanızı ve uygulamanızı eklersiniz.
AXI-Lite slave şablonu oluşturma
Tools → Create and Package New IP
→ Create a new AXI4 Peripheral
→ Interface Type: AXI4-Lite
→ Data Width: 32 bit
→ Number of Registers: 4 (veya ihtiyaca göre)
→ Finish → "Edit IP"
Vivado şunları üretir:
my_ip_v1_0.vhd — üst seviye wrapper
my_ip_v1_0_S00_AXI.vhd — AXI-Lite slave mantığı
Register haritası ekleme (VHDL)
-- Şablona eklenen özel register mantığı
-- REG0 (0x00): kontrol register'ı
-- REG1 (0x04): veri çıkışı
-- REG2 (0x08): durum (salt okunur)
-- REG3 (0x0C): kesme enable
-- Yazma işlemi (şablonun write bölümüne ekle)
when b"00" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
slv_reg0(byte_index*8+7 downto byte_index*8) <=
S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
-- Uygulama mantığı (entity port'larına bağla)
CTRL_OUT <= slv_reg0(7 downto 0); -- kontrol bitleri
DATA_OUT <= slv_reg1; -- veri çıkışı
slv_reg2 <= "000" & STATUS_IN; -- durum okuma
IRQ_EN <= slv_reg3(0); -- kesme etkinleştir
Verilog alternatifi
// AXI4-Lite yazma FSM (basitleştirilmiş)
always @(posedge S_AXI_ACLK) begin
if (!S_AXI_ARESETN) begin
reg_ctrl <= 32'h0;
reg_data <= 32'h0;
reg_irqen <= 32'h0;
end else if (slv_reg_wren) begin
case (axi_awaddr[3:2])
2'h0: reg_ctrl <= S_AXI_WDATA;
2'h1: reg_data <= S_AXI_WDATA;
// 2'h2: STATUS salt okunur — yazma yok
2'h3: reg_irqen <= S_AXI_WDATA;
endcase
end
end
// Okuma multiplexer
always @(*) begin
case (axi_araddr[3:2])
2'h0: reg_data_out = reg_ctrl;
2'h1: reg_data_out = reg_data;
2'h2: reg_data_out = {{31}}{1'b0}, status_in};
2'h3: reg_data_out = reg_irqen;
endcase
end
Bu bölümde
- Vivado sihirbazı AXI-Lite slave şablonunu (wrapper + slave logic) otomatik üretir
- Register haritası: slv_reg0–3 alanlarına mantık eklenerek özelleştirilir
- Salt okunur register: yazma durumunda yoksay; okuma multiplexer'da STATUS geri döndür
- VHDL ve Verilog şablonları Vivado tarafından her ikisi için de üretilebilir
03 AXI-Stream veri akışı periferali
AXI-Stream periferaller, sürekli akan veri üzerinde işlem yapar: filtreleme, şifreleme, sıkıştırma, protokol dönüştürme. Vivado'da AXI-Stream IP'ler AXI-DMA ile birlikte kullanılır.
AXI-Stream FIFO ile bağlantı
PS (AXI-DMA MM2S) → AXI4-Stream FIFO → Özel İşlemci → AXI4-Stream FIFO → PS (AXI-DMA S2MM) MM2S: Memory-to-Stream (DDR'dan PL'e veri gönder) S2MM: Stream-to-Memory (PL'den DDR'a veri yaz) AXI-DMA: iki kanallı (MM2S + S2MM) scatter-gather DMA
Basit AXI-Stream geçiş filtresi (Verilog)
module axis_pass_filter #(
parameter DATA_WIDTH = 32
)(
input wire aclk,
input wire aresetn,
// Slave (giriş)
input wire [DATA_WIDTH-1:0] s_tdata,
input wire s_tvalid,
output wire s_tready,
input wire s_tlast,
// Master (çıkış)
output wire [DATA_WIDTH-1:0] m_tdata,
output wire m_tvalid,
input wire m_tready,
output wire m_tlast,
// Kontrol (AXI-Lite'dan)
input wire [DATA_WIDTH-1:0] threshold
);
// Eşiği geçen örnekleri maskele
wire pass = (s_tdata <= threshold);
assign m_tdata = pass ? s_tdata : {DATA_WIDTH{1'b0}};
assign m_tvalid = s_tvalid;
assign s_tready = m_tready;
assign m_tlast = s_tlast;
endmodule
Bu bölümde
- AXI-Stream: TDATA/TVALID/TREADY/TLAST; handshake tabanlı akış kontrolü
- AXI-DMA: MM2S (DDR→PL) + S2MM (PL→DDR) — iki kanallı
- TLAST: AXI-DMA S2MM için paket sonu — zorunlu doğru kullanım
- Filtre örneği: eşik tabanlı maskeleme; threshold AXI-Lite'dan ayarlanır
04 Zamanlama kısıtları (XDC)
Zamanlama kısıtları (XDC — Xilinx Design Constraints), sentez ve yer-yönlendirme araçlarının hedef frekansı ve özel zamanlama gereksinimlerini bildiği dosyadır. Hatalı XDC, çalışmayan veya kararsız bir tasarımla sonuçlanır.
Temel saat kısıtı
## Birincil saat — 100 MHz PS FCLK0
create_clock -period 10.000 -name clk_100 \
[get_ports {FCLK_CLK0}]
## ZedBoard — harici 100 MHz osilatör (PL direkt)
create_clock -period 10.000 -name sys_clk \
[get_ports {sys_clk_p}]
## I/O zamanlama (AXI master/slave dışı GPIO)
set_input_delay -clock clk_100 2.0 [get_ports {btn_*}]
set_output_delay -clock clk_100 2.0 [get_ports {led_*}]
## Yanlış yol (false path) — asenkron reset
set_false_path -from [get_ports {cpu_resetn}]
## CDC — farklı saat etki alanları arası yol
set_false_path -from [get_clocks clk_100] \
-to [get_clocks clk_200]
Timing summary yorumlama
| Metrik | Anlamı | Hedef |
|---|---|---|
| WNS (Worst Negative Slack) | En kötü zamanlama açığı; pozitif = geçti | ≥ 0 ns |
| TNS (Total Negative Slack) | Toplam zamanlama açığı | 0 ns |
| WHS (Worst Hold Slack) | Hold zamanı en kötü durumu | ≥ 0 ns |
| WPWS (Worst Pulse Width Slack) | Minimum pulse genişliği | ≥ 0 ns |
WNS negatifse tasarım timing kapatmamıştır. Sentez parametrelerini sıkılaştırın (strategy: Performance_ExplorePostRoutePhysOpt), pipeline ekleyin veya hedef frekansı düşürün. Negatif slack ile bitstream üretmek donanım arızasına yol açar.
Bu bölümde
- create_clock: tüm birincil saatler XDC'de tanımlanmalı
- set_false_path: asenkron reset ve CDC yolları için
- WNS ≥ 0: tasarım timing'i kapattı — bitstream üretmeye hazır
- Negatif WNS: pipeline ekle, frekansı düşür veya sentez stratejisini değiştir
05 Bitstream üretimi ve BOOT.BIN
Vivado implementation sonrasında .bit dosyası üretilir. Zynq için bu dosya FSBL ve U-Boot ile birleştirilip BOOT.BIN olarak paketlenir.
Implementation ve bitstream
Synthesis → Implementation → Generate Bitstream
Synthesis: RTL → gate-level netlist (XDC uygulanır)
Implementation:
opt_design — optimizasyon
place_design — LUT/FF/BRAM yerleşimi
route_design — sinyal yönlendirme
phys_opt — post-route fiziksel optimizasyon
Generate Bitstream: .bit dosyası üretir
BOOT.BIN oluşturma (BIF dosyası)
// Zynq-7000 BOOT.BIN yapılandırması
the_ROM_image:
{
[bootloader] fsbl.elf // FSBL — OCM'de çalışır
design_1_wrapper.bit // PL bitstream
u-boot.elf // U-Boot
}
# Vitis veya Petalinux araçlarıyla
bootgen -arch zynq -image boot.bif -w on -o BOOT.BIN
# SD karta kopyala
cp BOOT.BIN /media/boot/
cp image.ub /media/boot/ # FIT imaj (kernel + DTB + initrd)
# veya TFTP ile U-Boot'tan yükle
# U-Boot prompt:
# tftpboot 0x3000000 image.ub && bootm 0x3000000
Partial bitstream (.pbin)
Kısmi yeniden yapılandırma (Partial Reconfiguration — PR) etkinleştirildiğinde, yalnızca PL'in belirli bir bölgesi yeniden programlanabilir. .pbin dosyası tam bitstream yerine kullanılır; çalışma süresi kesintisi minimuma iner.
Bu bölümde
- Implementation: synth → opt → place → route → phys_opt → bitstream
- BOOT.BIN: BIF dosyasıyla FSBL + bitstream + U-Boot birleştirme
- bootgen -arch zynq -image boot.bif -w on -o BOOT.BIN
- Partial bitstream: .pbin ile sadece PR bölgesi yeniden programlanır
06 Quartus Platform Designer (Qsys)
Intel Quartus Prime'ın Platform Designer (eski adıyla Qsys) aracı, Vivado Block Design'a karşılık gelen sistem entegrasyon ortamıdır. HPS ve FPGA bileşenlerini Avalon veya AXI veri yollarıyla bağlar.
Platform Designer bileşenleri
Platform Designer iş akışı
Quartus Prime → Tools → Platform Designer
→ HPS bileşenini ekle ve yapılandır
→ Özel IP bileşenlerini ekle (Component Editor ile)
→ Bağlantıları çiz (Avalon veya AXI)
→ Address Map düzenle
→ Generate HDL → Synthesis Files
Quartus: top-level projeye Platform Designer çıkışını dahil et
→ Analysis & Synthesis → Fitter → Assembler → .sof/.rbf
Bu bölümde
- Platform Designer: Qsys — Vivado Block Design Intel muadili
- Avalon-MM: Cyclone V'nin yerel veri yolu; AXI köprüsüyle standart IP bağlanır
- HPS Component: MIO, DDR, köprü yapılandırması tek yerden
- Çıkış: .sof (JTAG programlama) veya .rbf (runtime yükleme)
07 HPS-to-FPGA köprüleri yapılandırması
Cyclone V SoC'ta HPS ve FPGA arasındaki veri yolu köprüleri Platform Designer'da yapılandırılır. Her köprünün bant genişliği, gecikme ve adres eşlemesi farklıdır.
Köprü yapılandırma seçenekleri
| Köprü | Veri genişliği | Max frekans | Max bant |
|---|---|---|---|
| H2F (HPS→FPGA) | 32/64/128-bit | 250 MHz | ~4 GB/s |
| F2H (FPGA→HPS) | 32/64/128-bit | 250 MHz | ~4 GB/s |
| Lightweight H2F | 32-bit | 125 MHz | ~500 MB/s |
| F2H SDRAM | 128/256-bit | 200 MHz | ~6 GB/s |
Linux köprü yönetimi
// Cyclone V SoC — sysmgr üzerinden köprü kontrolü
// Kernel sürücüsü: drivers/fpga/altera-hps2fpga.c
// Kullanıcı alanından sysfs üzerinden:
// echo 1 > /sys/bus/platform/drivers/altera-hps2fpga/ff400000.bridge/enable
// veya devmem2 aracıyla SYSMGR.FPGAINTF register'ı:
// SYSMGR_BASE = 0xFFD08000
// FPGAINTF_EN_2 offset = 0x28
// bit[0]: H2F, bit[1]: LWH2F, bit[2]: F2H
#define SYSMGR_BASE 0xFFD08000UL
#define FPGAINTF_EN_2 0x28
volatile uint32_t *sysmgr = mmap_region(SYSMGR_BASE, 0x1000);
sysmgr[FPGAINTF_EN_2 / 4] |= (1 << 0) | (1 << 1); // H2F + LWH2F
Bu bölümde
- H2F (128-bit, 250 MHz): yüksek bant genişliği HPS→FPGA
- LWH2F (32-bit): düşük bant, düşük gecikme — CSR register erişimi
- F2H SDRAM: FPGA DMA → HPS DDR; en yüksek bant genişliği
- Linux'ta köprü: altera-hps2fpga sürücüsü veya SYSMGR register
08 Pratik: AXI-Lite PWM periferali
Bu bölümde Vivado'da AXI-Lite kontrol register'larına sahip, frekans ve görev döngüsü yazılımdan ayarlanabilir bir PWM (Pulse Width Modulation) periferali tasarlanacak ve Linux'tan kontrol edilecektir.
PWM register haritası
| Offset | Register | Açıklama |
|---|---|---|
| 0x00 | CTRL | bit[0]=enable, bit[1]=polarity |
| 0x04 | PERIOD | Periyot (saat döngüsü sayısı − 1) |
| 0x08 | DUTY | Yüksek süre (saat döngüsü sayısı) |
| 0x0C | STATUS | bit[0]=çalışıyor, bit[1]=periyot aşımı |
PWM çekirdeği (Verilog)
module pwm_core (
input wire clk,
input wire rst_n,
input wire enable,
input wire polarity,
input wire [31:0] period, // saat döngüsü sayısı - 1
input wire [31:0] duty, // yüksek süre
output reg pwm_out,
output wire running
);
reg [31:0] counter = 0;
assign running = enable;
always @(posedge clk) begin
if (!rst_n || !enable) begin
counter <= 0;
pwm_out <= polarity ? 1'b0 : 1'b1;
end else begin
if (counter >= period)
counter <= 0;
else
counter <= counter + 1;
if (counter < duty)
pwm_out <= polarity ? 1'b1 : 1'b0;
else
pwm_out <= polarity ? 1'b0 : 1'b1;
end
end
endmodule
Linux kullanıcı alanı — PWM kontrolü
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#define PWM_BASE 0x40000000UL
#define MAP_SIZE 0x10000UL
#define REG_CTRL 0x00
#define REG_PERIOD 0x04
#define REG_DUTY 0x08
#define REG_STATUS 0x0C
/* 100 MHz saat, 10 kHz PWM, %75 görev döngüsü */
#define CLK_HZ 100000000UL
#define PWM_HZ 10000UL
#define DUTY_PCT 75
int main(void)
{
uint32_t period = CLK_HZ / PWM_HZ - 1; // 9999
uint32_t duty = period * DUTY_PCT / 100; // 7499
int fd = open("/dev/mem", O_RDWR | O_SYNC);
volatile uint32_t *pwm =
mmap(NULL, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, PWM_BASE);
pwm[REG_CTRL / 4] = 0; /* durdur */
pwm[REG_PERIOD / 4] = period;
pwm[REG_DUTY / 4] = duty;
pwm[REG_CTRL / 4] = 1; /* enable, normal polarity */
printf("PWM: %u Hz, duty=%u/%u (%d%%)\n",
(uint32_t)PWM_HZ, duty, period, DUTY_PCT);
printf("STATUS: 0x%08X\n", pwm[REG_STATUS / 4]);
munmap((void *)pwm, MAP_SIZE);
close(fd);
return 0;
}
Gerçek üretim kodunda Linux PWM subsystem (CONFIG_PWM) üzerinden sysfs arayüzü (/sys/class/pwm/) kullanın. Platform driver yazan sürücü, pwm_chip yapısı aracılığıyla kernel PWM çerçevesine entegre olur. Böylece kullanıcı alanı uygulamaları donanımdan bağımsız kalır.
Bu bölümde
- PWM: 4 register (CTRL, PERIOD, DUTY, STATUS) — AXI-Lite üzerinden
- Period = CLK / PWM_HZ − 1; Duty = Period × duty% / 100
- Verilog: counter tabanlı; polarity invertible
- Üretimde: Linux PWM subsystem + pwm_chip driver — sysfs arayüzü