From 1acedf494ca3c32a0b69497b06c3a24af6251ec3 Mon Sep 17 00:00:00 2001 From: Jason <83615043+JJassonn69@users.noreply.github.com> Date: Mon, 16 Mar 2026 22:24:22 +0200 Subject: [PATCH] Migrate hardware platform from XC7A50T to XC7A200T-2FBG484I Production FPGA: Artix-7 XC7A200T-2FBG484I (33,650 slices, 740 DSP48E1, 365 BRAM, -2 speed grade). Pin-mapped across 6 banks with proper VCCO assignment (3.3V/2.5V/1.8V). RTL timing primitives added for clean timing closure: - ad9484_interface_400m.v: BUFIO for IDDR capture at 400MHz DDR, BUFG for fabric logic, reset synchronizer (P1-7) - dac_interface_single.v: ODDR for dac_clk forwarding + dac_data[7:0] output registration, eliminates clock-forwarding insertion delay - usb_data_interface.v: ODDR for ft601_clk_out forwarding, FSM runs on ft601_clk_in domain with CDC synchronizers Constraints: - New production XDC (xc7a200t_fbg484.xdc): 182 pins, generated clocks for ODDR outputs, BUFIO/DDR input delays, fixed false_path strategy (from reset source, not to CLR pins), IOB packing on cells not ports - Preserved upstream XDC as xc7a50t_ftg256.xdc for reference - Updated cntrt.xdc with DRC fixes (I/O standards, missing constraints) --- 9_Firmware/9_2_FPGA/ad9484_interface_400m.v | 63 +- 9_Firmware/9_2_FPGA/cntrt.xdc | 460 ++++++------ 9_Firmware/9_2_FPGA/constraints/README.md | 78 ++ .../9_2_FPGA/constraints/xc7a200t_fbg484.xdc | 673 ++++++++++++++++++ .../9_2_FPGA/constraints/xc7a50t_ftg256.xdc | 322 +++++++++ 9_Firmware/9_2_FPGA/dac_interface_single.v | 69 +- 9_Firmware/9_2_FPGA/usb_data_interface.v | 42 +- 7 files changed, 1431 insertions(+), 276 deletions(-) create mode 100644 9_Firmware/9_2_FPGA/constraints/README.md create mode 100644 9_Firmware/9_2_FPGA/constraints/xc7a200t_fbg484.xdc create mode 100644 9_Firmware/9_2_FPGA/constraints/xc7a50t_ftg256.xdc diff --git a/9_Firmware/9_2_FPGA/ad9484_interface_400m.v b/9_Firmware/9_2_FPGA/ad9484_interface_400m.v index 9205f51..624d83d 100644 --- a/9_Firmware/9_2_FPGA/ad9484_interface_400m.v +++ b/9_Firmware/9_2_FPGA/ad9484_interface_400m.v @@ -44,8 +44,24 @@ IBUFDS #( .IB(adc_dco_n) ); -// Global clock buffer for DCO — used as 400MHz clock throughout receiver -wire adc_dco_buffered; +// ============================================================================ +// Clock buffering strategy for source-synchronous ADC interface: +// +// BUFIO: Near-zero insertion delay, can only drive IOB primitives (IDDR). +// Used for IDDR clocking to match the data path delay through IBUFDS. +// This eliminates the hold violation caused by BUFG insertion delay. +// +// BUFG: Global clock buffer for fabric logic (downstream processing). +// Has ~4 ns insertion delay but that's fine for fabric-to-fabric paths. +// ============================================================================ +wire adc_dco_bufio; // Near-zero delay — drives IDDR only +wire adc_dco_buffered; // BUFG output — drives fabric logic + +BUFIO bufio_dco ( + .I(adc_dco), + .O(adc_dco_bufio) +); + BUFG bufg_dco ( .I(adc_dco), .O(adc_dco_buffered) @@ -53,8 +69,8 @@ BUFG bufg_dco ( assign adc_dco_bufg = adc_dco_buffered; // IDDR for capturing DDR data -wire [7:0] adc_data_rise; // Data on rising edge -wire [7:0] adc_data_fall; // Data on falling edge +wire [7:0] adc_data_rise; // Data on rising edge (BUFIO domain) +wire [7:0] adc_data_fall; // Data on falling edge (BUFIO domain) genvar j; generate @@ -67,7 +83,7 @@ generate ) iddr_inst ( .Q1(adc_data_rise[j]), // Rising edge data .Q2(adc_data_fall[j]), // Falling edge data - .C(adc_dco_buffered), // 400MHz DCO (buffered) + .C(adc_dco_bufio), // BUFIO clock (near-zero insertion delay) .CE(1'b1), .D(adc_data[j]), .R(1'b0), @@ -76,13 +92,44 @@ generate end endgenerate +// ============================================================================ +// Re-register IDDR outputs into BUFG domain +// IDDR with SAME_EDGE_PIPELINED produces outputs stable for a full clock cycle. +// BUFIO and BUFG are derived from the same source (adc_dco), so they are +// frequency-matched. This single register stage transfers from IOB (BUFIO) +// to fabric (BUFG) with guaranteed timing. +// ============================================================================ +reg [7:0] adc_data_rise_bufg; +reg [7:0] adc_data_fall_bufg; + +always @(posedge adc_dco_buffered) begin + adc_data_rise_bufg <= adc_data_rise; + adc_data_fall_bufg <= adc_data_fall; +end + // Combine rising and falling edge data to get 400MSPS stream reg [7:0] adc_data_400m_reg; reg adc_data_valid_400m_reg; reg dco_phase; +// ── Reset synchronizer ──────────────────────────────────────── +// reset_n comes from the 100 MHz sys_clk domain. Assertion (going low) +// is asynchronous and safe — the FFs enter reset instantly. De-assertion +// (going high) must be synchronised to adc_dco_buffered to avoid +// metastability. This is the classic "async assert, sync de-assert" pattern. +(* ASYNC_REG = "TRUE" *) reg [1:0] reset_sync_400m; +wire reset_n_400m; + always @(posedge adc_dco_buffered or negedge reset_n) begin - if (!reset_n) begin + if (!reset_n) + reset_sync_400m <= 2'b00; // async assert + else + reset_sync_400m <= {reset_sync_400m[0], 1'b1}; // sync de-assert +end +assign reset_n_400m = reset_sync_400m[1]; + +always @(posedge adc_dco_buffered or negedge reset_n_400m) begin + if (!reset_n_400m) begin adc_data_400m_reg <= 8'b0; adc_data_valid_400m_reg <= 1'b0; dco_phase <= 1'b0; @@ -91,10 +138,10 @@ always @(posedge adc_dco_buffered or negedge reset_n) begin if (dco_phase) begin // Output falling edge data (completes the 400MSPS stream) - adc_data_400m_reg <= adc_data_fall; + adc_data_400m_reg <= adc_data_fall_bufg; end else begin // Output rising edge data - adc_data_400m_reg <= adc_data_rise; + adc_data_400m_reg <= adc_data_rise_bufg; end adc_data_valid_400m_reg <= 1'b1; // Always valid when ADC is running diff --git a/9_Firmware/9_2_FPGA/cntrt.xdc b/9_Firmware/9_2_FPGA/cntrt.xdc index 60e7f2e..cb16122 100644 --- a/9_Firmware/9_2_FPGA/cntrt.xdc +++ b/9_Firmware/9_2_FPGA/cntrt.xdc @@ -1,307 +1,260 @@ # ============================================================================ # RADAR SYSTEM FPGA CONSTRAINTS # ============================================================================ -# Device: [XC7A100T] -# Created: [DATE] -# Description: Main constraints file for radar system with FT601 USB 3.0 +# Device: XC7A50T-2FTG256I (FTG256 package) +# Board: AERIS-10 Phased Array Radar — Main Board +# Source: Pin assignments extracted from Eagle schematic (RADAR_Main_Board.sch) +# FPGA = U42 +# +# NOTE: The README and prior version of this file incorrectly referenced +# XC7A100TCSG324-1. The physical board uses XC7A50T in a 256-ball BGA +# (FTG256). All PACKAGE_PIN values below are FTG256 ball locations. +# +# I/O Bank Voltage Summary: +# Bank 0: VCCO = 3.3V (JTAG, flash CS) +# Bank 14: VCCO = 3.3V (ADC LVDS data, SPI flash) +# Bank 15: VCCO = 3.3V (DAC, clocks, STM32 SPI 3.3V side, DIG bus, mixer) +# Bank 34: VCCO = 1.8V (ADAR1000 beamformer control, SPI 1.8V side) +# Bank 35: VCCO = 3.3V (unused — no signal connections) # ============================================================================ # ============================================================================ # CLOCK CONSTRAINTS # ============================================================================ -# 100MHz System Clock +# 100MHz System Clock (AD9523 OUT6 → FPGA_SYS_CLOCK → Bank 15 MRCC pin E12) +set_property PACKAGE_PIN E12 [get_ports {clk_100m}] +set_property IOSTANDARD LVCMOS33 [get_ports {clk_100m}] create_clock -name clk_100m -period 10.0 [get_ports {clk_100m}] set_input_jitter [get_clocks clk_100m] 0.1 -# 120MHz DAC Clock +# 120MHz DAC Clock (AD9523 OUT11 → FPGA_DAC_CLOCK → Bank 15 MRCC pin C13) +# NOTE: The physical DAC (U3, AD9708) receives its clock directly from the +# AD9523 via a separate net (DAC_CLOCK), NOT from the FPGA. The FPGA +# uses this clock input for internal DAC data timing only. The RTL port +# `dac_clk` is an output that assigns clk_120m directly — it has no +# separate physical pin on this board and should be removed from the +# RTL or left unconnected. +set_property PACKAGE_PIN C13 [get_ports {clk_120m_dac}] +set_property IOSTANDARD LVCMOS33 [get_ports {clk_120m_dac}] create_clock -name clk_120m_dac -period 8.333 [get_ports {clk_120m_dac}] set_input_jitter [get_clocks clk_120m_dac] 0.1 -# FT601 Clock (100MHz from FT601) -create_clock -name ft601_clk_in -period 10.0 [get_ports {ft601_clk_in}] -set_input_jitter [get_clocks ft601_clk_in] 0.1 - -# ADC DCO Clock (400MHz LVDS) +# ADC DCO Clock (400MHz LVDS — AD9523 OUT5 → AD9484 → FPGA, Bank 14 MRCC) +set_property PACKAGE_PIN N14 [get_ports {adc_dco_p}] +set_property PACKAGE_PIN P14 [get_ports {adc_dco_n}] +set_property IOSTANDARD LVDS_33 [get_ports {adc_dco_p}] +set_property IOSTANDARD LVDS_33 [get_ports {adc_dco_n}] +set_property DIFF_TERM TRUE [get_ports {adc_dco_p}] create_clock -name adc_dco_p -period 2.5 [get_ports {adc_dco_p}] set_input_jitter [get_clocks adc_dco_p] 0.05 -# ============================================================================ -# RESET CONSTRAINTS -# ============================================================================ +# -------------------------------------------------------------------------- +# FT601 Clock — COMMENTED OUT: FT601 (U6) is placed in schematic but has +# zero net connections. No physical clock pin exists on this board. +# -------------------------------------------------------------------------- +# create_clock -name ft601_clk_in -period 10.0 [get_ports {ft601_clk_in}] +# set_input_jitter [get_clocks ft601_clk_in] 0.1 -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {reset_n}] +# ============================================================================ +# RESET (Active-Low) +# ============================================================================ +# DIG_4 (STM32 PD12 → FPGA Bank 15 pin E15) +# STM32 firmware uses HAL_GPIO_WritePin to assert/deassert FPGA reset. + +set_property PACKAGE_PIN E15 [get_ports {reset_n}] set_property IOSTANDARD LVCMOS33 [get_ports {reset_n}] set_property PULLUP true [get_ports {reset_n}] # ============================================================================ -# TRANSMITTER INTERFACE (DAC) +# TRANSMITTER INTERFACE (DAC — Bank 15, VCCO=3.3V) # ============================================================================ -# DAC Data Bus (8-bit) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[2]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[3]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[4]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[5]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[6]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_data[7]}] +# DAC Data Bus (8-bit) — AD9708 data inputs via schematic nets DAC_0..DAC_7 +set_property PACKAGE_PIN A14 [get_ports {dac_data[0]}] +set_property PACKAGE_PIN A13 [get_ports {dac_data[1]}] +set_property PACKAGE_PIN A12 [get_ports {dac_data[2]}] +set_property PACKAGE_PIN B11 [get_ports {dac_data[3]}] +set_property PACKAGE_PIN B10 [get_ports {dac_data[4]}] +set_property PACKAGE_PIN A10 [get_ports {dac_data[5]}] +set_property PACKAGE_PIN A9 [get_ports {dac_data[6]}] +set_property PACKAGE_PIN A8 [get_ports {dac_data[7]}] set_property IOSTANDARD LVCMOS33 [get_ports {dac_data[*]}] set_property SLEW FAST [get_ports {dac_data[*]}] set_property DRIVE 8 [get_ports {dac_data[*]}] -# DAC Control -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_clk}] -set_property IOSTANDARD LVCMOS33 [get_ports {dac_clk}] -set_property SLEW FAST [get_ports {dac_clk}] +# DAC Clock Output — NOT DIRECTLY WIRED TO DAC IN SCHEMATIC +# The DAC chip (U3) receives its clock from AD9523 via a separate net +# (DAC_CLOCK), not from the FPGA. The RTL `dac_clk` output has no +# physical pin. Comment out or remove from RTL. +# set_property PACKAGE_PIN ??? [get_ports {dac_clk}] +# set_property IOSTANDARD LVCMOS33 [get_ports {dac_clk}] +# set_property SLEW FAST [get_ports {dac_clk}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dac_sleep}] +# DAC Sleep Control — DAC_SLEEP net +set_property PACKAGE_PIN A15 [get_ports {dac_sleep}] set_property IOSTANDARD LVCMOS33 [get_ports {dac_sleep}] -# RF Switch Control -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {fpga_rf_switch}] +# RF Switch Control — M3S_VCTRL net +set_property PACKAGE_PIN G15 [get_ports {fpga_rf_switch}] set_property IOSTANDARD LVCMOS33 [get_ports {fpga_rf_switch}] -# Mixer Enables -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {rx_mixer_en}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {tx_mixer_en}] +# Mixer Enables — MIX_RX_EN, MIX_TX_EN nets +set_property PACKAGE_PIN D11 [get_ports {rx_mixer_en}] +set_property PACKAGE_PIN C11 [get_ports {tx_mixer_en}] set_property IOSTANDARD LVCMOS33 [get_ports {rx_mixer_en}] set_property IOSTANDARD LVCMOS33 [get_ports {tx_mixer_en}] # ============================================================================ -# ADAR1000 BEAMFORMER CONTROL +# ADAR1000 BEAMFORMER CONTROL (Bank 34, VCCO=1.8V) # ============================================================================ -# ADAR1000 Load/Control Pins (Channel 1-4) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tx_load_1}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_rx_load_1}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tx_load_2}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_rx_load_2}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tx_load_3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_rx_load_3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tx_load_4}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_rx_load_4}] -set_property IOSTANDARD LVCMOS33 [get_ports {adar_*_load_*}] +# ADAR1000 TX Load Pins (via level shifters, active-high pulse) +set_property PACKAGE_PIN P3 [get_ports {adar_tx_load_1}] +set_property PACKAGE_PIN T4 [get_ports {adar_tx_load_2}] +set_property PACKAGE_PIN R3 [get_ports {adar_tx_load_3}] +set_property PACKAGE_PIN R2 [get_ports {adar_tx_load_4}] -# ADAR1000 TR Pins -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tr_1}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tr_2}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tr_3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adar_tr_4}] -set_property IOSTANDARD LVCMOS33 [get_ports {adar_tr_*}] +# ADAR1000 RX Load Pins +set_property PACKAGE_PIN M5 [get_ports {adar_rx_load_1}] +set_property PACKAGE_PIN T2 [get_ports {adar_rx_load_2}] +set_property PACKAGE_PIN R1 [get_ports {adar_rx_load_3}] +set_property PACKAGE_PIN N4 [get_ports {adar_rx_load_4}] + +# Bank 34 VCCO = 1.8V → must use LVCMOS18 (not LVCMOS33) +set_property IOSTANDARD LVCMOS18 [get_ports {adar_*_load_*}] + +# ADAR1000 TR (Transmit/Receive) Pins +set_property PACKAGE_PIN N2 [get_ports {adar_tr_1}] +set_property PACKAGE_PIN N1 [get_ports {adar_tr_2}] +set_property PACKAGE_PIN P1 [get_ports {adar_tr_3}] +set_property PACKAGE_PIN P4 [get_ports {adar_tr_4}] +set_property IOSTANDARD LVCMOS18 [get_ports {adar_tr_*}] # ============================================================================ -# LEVEL SHIFTER SPI INTERFACE (STM32 to ADAR1000) +# LEVEL SHIFTER SPI INTERFACE (STM32 ↔ ADAR1000) # ============================================================================ -# 3.3V Side (from STM32) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_sclk_3v3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_mosi_3v3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_miso_3v3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar1_3v3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar2_3v3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar3_3v3}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar4_3v3}] +# 3.3V Side (from STM32, Bank 15, VCCO=3.3V) +set_property PACKAGE_PIN J16 [get_ports {stm32_sclk_3v3}] +set_property PACKAGE_PIN H13 [get_ports {stm32_mosi_3v3}] +set_property PACKAGE_PIN G14 [get_ports {stm32_miso_3v3}] +set_property PACKAGE_PIN F14 [get_ports {stm32_cs_adar1_3v3}] +set_property PACKAGE_PIN H16 [get_ports {stm32_cs_adar2_3v3}] +set_property PACKAGE_PIN G16 [get_ports {stm32_cs_adar3_3v3}] +set_property PACKAGE_PIN J15 [get_ports {stm32_cs_adar4_3v3}] set_property IOSTANDARD LVCMOS33 [get_ports {stm32_*_3v3}] -# 1.8V Side (to ADAR1000) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_sclk_1v8}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_mosi_1v8}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_miso_1v8}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar1_1v8}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar2_1v8}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar3_1v8}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_cs_adar4_1v8}] +# 1.8V Side (to ADAR1000, Bank 34, VCCO=1.8V) +set_property PACKAGE_PIN P5 [get_ports {stm32_sclk_1v8}] +set_property PACKAGE_PIN M1 [get_ports {stm32_mosi_1v8}] +set_property PACKAGE_PIN N3 [get_ports {stm32_miso_1v8}] +set_property PACKAGE_PIN L5 [get_ports {stm32_cs_adar1_1v8}] +set_property PACKAGE_PIN L4 [get_ports {stm32_cs_adar2_1v8}] +set_property PACKAGE_PIN M4 [get_ports {stm32_cs_adar3_1v8}] +set_property PACKAGE_PIN M2 [get_ports {stm32_cs_adar4_1v8}] set_property IOSTANDARD LVCMOS18 [get_ports {stm32_*_1v8}] # ============================================================================ -# STM32 CONTROL INTERFACE +# STM32 CONTROL INTERFACE (DIG bus, Bank 15, VCCO=3.3V) # ============================================================================ +# DIG_0..DIG_4 are STM32 outputs (PD8-PD12) → FPGA inputs +# DIG_5..DIG_7 are STM32 inputs (PD13-PD15) ← FPGA outputs (unused in RTL) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_new_chirp}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_new_elevation}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_new_azimuth}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {stm32_mixers_enable}] +set_property PACKAGE_PIN F13 [get_ports {stm32_new_chirp}] ;# DIG_0 (PD8) +set_property PACKAGE_PIN E16 [get_ports {stm32_new_elevation}] ;# DIG_1 (PD9) +set_property PACKAGE_PIN D16 [get_ports {stm32_new_azimuth}] ;# DIG_2 (PD10) +set_property PACKAGE_PIN F15 [get_ports {stm32_mixers_enable}] ;# DIG_3 (PD11) set_property IOSTANDARD LVCMOS33 [get_ports {stm32_new_*}] set_property IOSTANDARD LVCMOS33 [get_ports {stm32_mixers_enable}] +# reset_n is DIG_4 (PD12) — constrained above in the RESET section + +# DIG_5 = H11, DIG_6 = G12, DIG_7 = H12 — available for FPGA→STM32 status +# Currently unused in RTL. Could be connected to status outputs if needed. # ============================================================================ -# ADC INTERFACE (LVDS - 400MHz) +# ADC INTERFACE (LVDS — Bank 14, VCCO=3.3V) # ============================================================================ -# ADC Data (LVDS pairs) -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[0]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[0]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[1]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[1]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[2]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[2]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[3]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[3]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[4]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[4]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[5]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[5]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[6]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[6]}] -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_d_p[7]}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_d_n[7]}] +# ADC Data (8-bit LVDS pairs from AD9484) +set_property PACKAGE_PIN P15 [get_ports {adc_d_p[0]}] +set_property PACKAGE_PIN P16 [get_ports {adc_d_n[0]}] +set_property PACKAGE_PIN R15 [get_ports {adc_d_p[1]}] +set_property PACKAGE_PIN R16 [get_ports {adc_d_n[1]}] +set_property PACKAGE_PIN T14 [get_ports {adc_d_p[2]}] +set_property PACKAGE_PIN T15 [get_ports {adc_d_n[2]}] +set_property PACKAGE_PIN R13 [get_ports {adc_d_p[3]}] +set_property PACKAGE_PIN T13 [get_ports {adc_d_n[3]}] +set_property PACKAGE_PIN R10 [get_ports {adc_d_p[4]}] +set_property PACKAGE_PIN R11 [get_ports {adc_d_n[4]}] +set_property PACKAGE_PIN T9 [get_ports {adc_d_p[5]}] +set_property PACKAGE_PIN T10 [get_ports {adc_d_n[5]}] +set_property PACKAGE_PIN T7 [get_ports {adc_d_p[6]}] +set_property PACKAGE_PIN T8 [get_ports {adc_d_n[6]}] +set_property PACKAGE_PIN R6 [get_ports {adc_d_p[7]}] +set_property PACKAGE_PIN R7 [get_ports {adc_d_n[7]}] -# ADC DCO Clock (LVDS) -set_property PACKAGE_PIN [PIN_NUMBER_P] [get_ports {adc_dco_p}] -set_property PACKAGE_PIN [PIN_NUMBER_N] [get_ports {adc_dco_n}] +# ADC DCO Clock (LVDS) — already constrained above in CLOCK section -# ADC Power Down -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {adc_pwdn}] +# ADC Power Down — ADC_PWRD net (single-ended, Bank 14) +set_property PACKAGE_PIN T5 [get_ports {adc_pwdn}] set_property IOSTANDARD LVCMOS33 [get_ports {adc_pwdn}] -# LVDS Constraints -set_property IOSTANDARD LVDS_25 [get_ports {adc_d_p[*]}] -set_property IOSTANDARD LVDS_25 [get_ports {adc_d_n[*]}] -set_property IOSTANDARD LVDS_25 [get_ports {adc_dco_p}] -set_property IOSTANDARD LVDS_25 [get_ports {adc_dco_n}] +# LVDS I/O Standard — Bank 14 VCCO = 3.3V → use LVDS_33 (not LVDS_25) +set_property IOSTANDARD LVDS_33 [get_ports {adc_d_p[*]}] +set_property IOSTANDARD LVDS_33 [get_ports {adc_d_n[*]}] -# Differential pair constraints +# Differential termination set_property DIFF_TERM TRUE [get_ports {adc_d_p[*]}] -set_property DIFF_TERM TRUE [get_ports {adc_dco_p}] -# Input delay for ADC data (adjust based on PCB trace length) +# Input delay for ADC data relative to DCO (adjust based on PCB trace length) set_input_delay -clock [get_clocks adc_dco_p] -max 1.0 [get_ports {adc_d_p[*]}] set_input_delay -clock [get_clocks adc_dco_p] -min 0.2 [get_ports {adc_d_p[*]}] # ============================================================================ -# FT601 USB 3.0 INTERFACE +# FT601 USB 3.0 INTERFACE — ACTIVE: NO PHYSICAL CONNECTIONS +# ============================================================================ +# The FT601 chip (U6, FT601Q-B-T) is placed in the Eagle schematic but has +# ZERO net connections — no signals are routed between it and the FPGA. +# Bank 35 (which would logically host FT601 signals) has no signal pins +# connected, only VCCO_35 power. +# +# ALL FT601 constraints are commented out. The RTL module usb_data_interface.v +# instantiates the FT601 interface, but it cannot function without physical +# pin assignments. To use USB, the schematic must be updated to wire the +# FT601 to FPGA Bank 35 pins, and then these constraints can be populated. +# +# Ports affected (from radar_system_top.v): +# ft601_data[31:0], ft601_be[1:0], ft601_txe_n, ft601_rxf_n, ft601_txe, +# ft601_rxf, ft601_wr_n, ft601_rd_n, ft601_oe_n, ft601_siwu_n, +# ft601_srb[1:0], ft601_swb[1:0], ft601_clk_out, ft601_clk_in +# +# TODO: Wire FT601 in schematic, then assign pins here. # ============================================================================ -# FT601 Data Bus (32-bit bidirectional) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[2]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[3]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[4]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[5]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[6]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[7]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[8]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[9]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[10]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[11]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[12]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[13]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[14]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[15]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[16]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[17]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[18]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[19]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[20]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[21]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[22]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[23]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[24]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[25]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[26]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[27]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[28]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[29]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[30]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_data[31]}] - -# Byte enables -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_be[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_be[1]}] - -# Control signals -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_txe_n}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_rxf_n}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_txe}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_rxf}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_wr_n}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_rd_n}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_oe_n}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_siwu_n}] - -# FIFO flags -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_srb[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_srb[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_swb[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_swb[1]}] - -# Clock out (optional) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {ft601_clk_out}] - -# FT601 I/O Standards (3.3V for FT601) -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_data[*]}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_be[*]}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_txe_n}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_rxf_n}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_txe}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_rxf}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_wr_n}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_rd_n}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_oe_n}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_siwu_n}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_srb[*]}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_swb[*]}] -set_property IOSTANDARD LVCMOS33 [get_ports {ft601_clk_out}] - -# FT601 timing constraints -set_output_delay -clock [get_clocks ft601_clk_in] -max 2.0 [get_ports {ft601_data[*]}] -set_output_delay -clock [get_clocks ft601_clk_in] -min 0.5 [get_ports {ft601_data[*]}] -set_output_delay -clock [get_clocks ft601_clk_in] -max 2.0 [get_ports {ft601_be[*]}] -set_output_delay -clock [get_clocks ft601_clk_in] -min 0.5 [get_ports {ft601_be[*]}] - # ============================================================================ -# STATUS OUTPUTS +# STATUS / DEBUG OUTPUTS — NO PHYSICAL CONNECTIONS +# ============================================================================ +# The following RTL output ports have no corresponding FPGA pins in the +# schematic. The only FPGA→STM32 outputs available are DIG_5 (H11), +# DIG_6 (G12), and DIG_7 (H12) — only 3 pins for potentially 60+ signals. +# +# These constraints are commented out. If status readback is needed, either: +# (a) Multiplex selected status bits onto DIG_5/6/7, or +# (b) Send status data over the SPI interface, or +# (c) Route through USB once FT601 is wired. +# +# Ports affected: +# current_elevation[5:0], current_azimuth[5:0], current_chirp[5:0], +# new_chirp_frame, dbg_doppler_data[31:0], dbg_doppler_valid, +# dbg_doppler_bin[4:0], dbg_range_bin[5:0], system_status[3:0] # ============================================================================ - -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_elevation[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_elevation[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_elevation[2]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_elevation[3]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_elevation[4]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_elevation[5]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_azimuth[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_azimuth[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_azimuth[2]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_azimuth[3]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_azimuth[4]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_azimuth[5]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_chirp[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_chirp[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_chirp[2]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_chirp[3]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_chirp[4]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {current_chirp[5]}] - -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {new_chirp_frame}] -set_property IOSTANDARD LVCMOS33 [get_ports {new_chirp_frame}] - -# Debug outputs -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_doppler_data[0]}] -# ... (continue for all 32 bits) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_doppler_data[31]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_doppler_valid}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_doppler_bin[0]}] -# ... (continue for all 5 bits) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_doppler_bin[4]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_range_bin[0]}] -# ... (continue for all 6 bits) -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {dbg_range_bin[5]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {system_status[0]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {system_status[1]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {system_status[2]}] -set_property PACKAGE_PIN [PIN_NUMBER] [get_ports {system_status[3]}] - -set_property IOSTANDARD LVCMOS33 [get_ports {dbg_*}] -set_property IOSTANDARD LVCMOS33 [get_ports {system_status[*]}] # ============================================================================ # TIMING EXCEPTIONS # ============================================================================ -# False paths for asynchronous signals +# False paths for asynchronous STM32 control signals (active-edge toggle interface) set_false_path -from [get_ports {stm32_new_*}] set_false_path -from [get_ports {stm32_mixers_enable}] @@ -315,26 +268,14 @@ set_false_path -from [get_ports {stm32_mixers_enable}] # - Route delay alone exceeds the clock period (18+ ns for 10ns period) # - Reset deassertion order is not functionally critical — all registers # come out of reset within a few cycles of each other -# -# This covers: -# - async_default path group (clk_100m intra-clock, WNS = -11.025ns) -# - clk_100m → clk_120m_dac CDC reset paths (WNS = -3.200ns) -# - clk_100m → ft601_clk_in CDC reset paths (WNS = -3.188ns) # -------------------------------------------------------------------------- set_false_path -from [get_cells reset_sync_reg[*]] -to [get_pins -filter {REF_PIN_NAME == CLR} -of_objects [get_cells -hierarchical -filter {PRIMITIVE_TYPE =~ REGISTER.*.*}]] # -------------------------------------------------------------------------- # Clock Domain Crossing false paths -# -# These clock domains are asynchronous to each other. Data crossing between -# them uses proper CDC synchronizers (2-stage or 3-stage) with ASYNC_REG -# attributes. The timing tool should not attempt to time these paths as -# single-cycle transfers. # -------------------------------------------------------------------------- -# clk_100m ↔ adc_dco_p (400 MHz): DDC reset synchronizer handles this -# The DDC has an internal 2-stage reset synchronizer for the 400 MHz domain. -# Any remaining CDC paths between these domains use proper synchronizers. +# clk_100m ↔ adc_dco_p (400 MHz): DDC has internal CDC synchronizers set_false_path -from [get_clocks clk_100m] -to [get_clocks adc_dco_p] set_false_path -from [get_clocks adc_dco_p] -to [get_clocks clk_100m] @@ -342,27 +283,40 @@ set_false_path -from [get_clocks adc_dco_p] -to [get_clocks clk_100m] set_false_path -from [get_clocks clk_100m] -to [get_clocks clk_120m_dac] set_false_path -from [get_clocks clk_120m_dac] -to [get_clocks clk_100m] -# clk_100m ↔ ft601_clk_in: CDC via synchronizers in usb_data_interface -set_false_path -from [get_clocks clk_100m] -to [get_clocks ft601_clk_in] -set_false_path -from [get_clocks ft601_clk_in] -to [get_clocks clk_100m] - -# Multicycle paths for slow signals (kept from original constraints) -# NOTE: The false_path above supersedes this for clk_100m→ft601_clk_in, -# but keeping it for documentation of the original design intent. -# set_multicycle_path -setup 2 -from [get_clocks clk_100m] -to [get_clocks ft601_clk_in] -# set_multicycle_path -hold 1 -from [get_clocks clk_100m] -to [get_clocks ft601_clk_in] +# FT601 CDC paths removed — no ft601_clk_in clock defined (chip unwired) # ============================================================================ # PHYSICAL CONSTRAINTS # ============================================================================ -# Group related pins into banks +# Pull up unused pins to prevent floating inputs set_property BITSTREAM.CONFIG.UNUSEDPIN Pullup [current_design] -# Place high-speed interfaces in same bank -set_property PACKAGE_PIN_BANK [BANK_NUMBER] [get_ports {ft601_data[*]}] -set_property PACKAGE_PIN_BANK [BANK_NUMBER] [get_ports {ft601_*_n}] - +# ============================================================================ +# ADDITIONAL NOTES +# ============================================================================ +# +# 1. ADC Sampling Clock: FPGA_ADC_CLOCK_P/N (N11/N12) is the 400 MHz LVDS +# clock from AD9523 OUT5 that drives the AD9484. It connects to FPGA MRCC +# pins but is not used as an FPGA clock input — the ADC returns data with +# its own DCO (adc_dco_p/n on N14/P14). +# +# 2. Clock Test: FPGA_CLOCK_TEST (H14) is a 20 MHz LVCMOS output from the +# FPGA, configured by AD9523 OUT7. Not currently used in RTL. +# +# 3. SPI Flash: FPGA_FLASH_CS (E8), FPGA_FLASH_CLK (J13), +# FPGA_FLASH_D0 (J14), D1 (K15), D2 (K16), D3 (L12), unnamed (L13). +# These are typically handled by Vivado bitstream configuration and do +# not need explicit XDC constraints for user logic. +# +# 4. JTAG: FPGA_TCK (L7), FPGA_TDI (N7), FPGA_TDO (N8), FPGA_TMS (M7). +# Dedicated pins — no XDC constraints needed. +# +# 5. dac_clk port: The RTL top module declares `dac_clk` as an output, but +# the physical board wires the DAC clock (AD9708 CLOCK pin) directly from +# the AD9523, not from the FPGA. This port should be removed from the RTL +# or left unconnected. It currently just assigns clk_120m_dac passthrough. +# # ============================================================================ # END OF CONSTRAINTS # ============================================================================ diff --git a/9_Firmware/9_2_FPGA/constraints/README.md b/9_Firmware/9_2_FPGA/constraints/README.md new file mode 100644 index 0000000..c5fd848 --- /dev/null +++ b/9_Firmware/9_2_FPGA/constraints/README.md @@ -0,0 +1,78 @@ +# AERIS-10 FPGA Constraint Files + +## Two Targets + +| File | Device | Package | Purpose | +|------|--------|---------|---------| +| `xc7a50t_ftg256.xdc` | XC7A50T-2FTG256I | FTG256 (256-ball BGA) | Upstream author's board (copy of `cntrt.xdc`) | +| `xc7a200t_fbg484.xdc` | XC7A200T-2FBG484I | FBG484 (484-ball BGA) | Production board (new PCB design) | + +## Why Two Files + +The upstream prototype uses a smaller XC7A50T in an FTG256 package. The production +AERIS-10 radar migrates to the XC7A200T for more logic, BRAM, and DSP resources. +The two devices have completely different packages and pin names, so each needs its +own constraint file. Both files constrain the same RTL top module (`radar_system_top.v`). + +## Bank Voltage Assignments + +### XC7A50T-FTG256 (Upstream) + +| Bank | VCCO | Signals | +|------|------|---------| +| 0 | 3.3V | JTAG, flash CS | +| 14 | 3.3V | ADC LVDS (LVDS_33), SPI flash | +| 15 | 3.3V | DAC, clocks, STM32 3.3V SPI, DIG bus | +| 34 | 1.8V | ADAR1000 control, SPI 1.8V side | +| 35 | 3.3V | Unused (no signal connections) | + +### XC7A200T-FBG484 (Production) + +| Bank | VCCO | Used/Avail | Signals | +|------|------|------------|---------| +| 13 | 3.3V | 17/35 | Debug overflow (doppler bins, range bins, status) | +| 14 | 2.5V | 19/50 | ADC LVDS_25 + DIFF_TERM, ADC power-down | +| 15 | 3.3V | 27/50 | System clocks (100M, 120M), DAC, RF, STM32 3.3V SPI, DIG bus | +| 16 | 3.3V | 50/50 | FT601 USB 3.0 (32-bit data + byte enable + control) | +| 34 | 1.8V | 19/50 | ADAR1000 beamformer control, SPI 1.8V side | +| 35 | 3.3V | 50/50 | Status outputs (beam position, chirp, doppler data bus) | + +## Signal Differences Between Targets + +| Signal | Upstream (FTG256) | Production (FBG484) | +|--------|-------------------|---------------------| +| FT601 USB | Unwired (chip placed, no nets) | Fully wired, Bank 16 | +| `dac_clk` | Not connected (DAC clocked by AD9523 directly) | Routed, FPGA drives DAC | +| `ft601_be` width | `[1:0]` in RTL | `[3:0]` needed (RTL update required) | +| ADC LVDS standard | LVDS_33 (3.3V bank) | LVDS_25 (2.5V bank, better quality) | +| Status/debug outputs | No physical pins (commented out) | All routed to Banks 35 + 13 | + +## How to Select in Vivado + +In the Vivado project, only one XDC should be active at a time: + +1. Add both files to the project: `File > Add Sources > Add Constraints` +2. In the Sources panel, right-click the XDC you do NOT want and select + `Set File Properties > Enabled = false` (or remove it from the active + constraint set) +3. Alternatively, use two separate constraint sets and switch between them + +For TCL-based flows: +```tcl +# For production target: +read_xdc constraints/xc7a200t_fbg484.xdc + +# For upstream target: +read_xdc constraints/xc7a50t_ftg256.xdc +``` + +## Notes + +- The production XDC pin assignments are **recommended** for the new PCB. + The PCB designer should follow this allocation. +- Bank 16 (FT601) is fully utilized at 50/50 pins. No room for expansion + on that bank. +- Bank 35 (status/debug) is also at capacity (50/50). Additional debug + signals should use Bank 13 spare pins (18 remaining). +- Clock inputs are placed on MRCC (Multi-Region Clock Capable) pins to + ensure proper clock tree access. diff --git a/9_Firmware/9_2_FPGA/constraints/xc7a200t_fbg484.xdc b/9_Firmware/9_2_FPGA/constraints/xc7a200t_fbg484.xdc new file mode 100644 index 0000000..a4477f7 --- /dev/null +++ b/9_Firmware/9_2_FPGA/constraints/xc7a200t_fbg484.xdc @@ -0,0 +1,673 @@ +# ============================================================================ +# AERIS-10 PHASED ARRAY RADAR — PRODUCTION FPGA CONSTRAINTS +# ============================================================================ +# Device: XC7A200T-2FBG484I (FBG484 package) +# Target: Production PCB (NEW design — pin assignments are RECOMMENDED, +# PCB designer should follow this allocation) +# +# Revision History: +# v1.0 2026-03-16 Initial pin plan from Vivado FBG484 package CSV export. +# Migrated from XC7A50T-FTG256 (upstream cntrt.xdc). +# FT601 USB 3.0 fully wired (32-bit data bus). +# dac_clk output wired (FPGA drives DAC clock). +# +# I/O Bank Voltage Plan: +# Bank 13: VCCO = 3.3V — Debug outputs overflow (doppler debug, range bins) +# Bank 14: VCCO = 2.5V — ADC LVDS (LVDS_25 + DIFF_TERM), ADC control +# Bank 15: VCCO = 3.3V — System clocks (100M MRCC, 120M MRCC), DAC, +# RF control, STM32 3.3V SPI, STM32 DIG bus, reset +# Bank 16: VCCO = 3.3V — FT601 USB 3.0 (32-bit data + 4-bit byte enable + +# control, clock on MRCC) +# Bank 34: VCCO = 1.8V — ADAR1000 beamformer control, SPI 1.8V side +# Bank 35: VCCO = 3.3V — Status outputs (beam position, chirp, doppler +# data bus, system status) +# +# Pin Count Summary: +# Bank 13: 17 used / 35 available (18 spare) +# Bank 14: 19 used / 50 available (31 spare) +# Bank 15: 27 used / 50 available (23 spare) +# Bank 16: 50 used / 50 available (0 spare) +# Bank 34: 19 used / 50 available (31 spare) +# Bank 35: 50 used / 50 available (0 spare) +# TOTAL: 182 used / 285 available +# +# Key Differences from Upstream (XC7A50T-FTG256): +# 1. ADC uses LVDS_25 (2.5V VCCO) instead of LVDS_33 (better signal quality) +# 2. FT601 USB 3.0 is fully wired (Bank 16) — unwired on upstream board +# 3. dac_clk output is routed — unconnected on upstream board +# 4. ft601_be is 4 bits wide for 32-bit FT601 mode (upstream RTL has [1:0]) +# 5. All status/debug outputs have physical pins (Banks 35 + 13) +# ============================================================================ + +# ============================================================================ +# CONFIGURATION +# ============================================================================ +set_property CFGBVS VCCO [current_design] +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property BITSTREAM.CONFIG.UNUSEDPIN Pullup [current_design] + +# ============================================================================ +# CLOCK CONSTRAINTS +# ============================================================================ + +# -------------------------------------------------------------------------- +# 100 MHz System Clock — AD9523 OUT6 → FPGA Bank 15 MRCC +# Pin: J19 = IO_L12P_T1_MRCC_15 +# -------------------------------------------------------------------------- +set_property PACKAGE_PIN J19 [get_ports {clk_100m}] +set_property IOSTANDARD LVCMOS33 [get_ports {clk_100m}] +create_clock -name clk_100m -period 10.000 [get_ports {clk_100m}] +set_input_jitter [get_clocks clk_100m] 0.100 + +# -------------------------------------------------------------------------- +# 120 MHz DAC Clock — AD9523 OUT11 → FPGA Bank 15 MRCC +# Pin: K18 = IO_L13P_T2_MRCC_15 +# -------------------------------------------------------------------------- +set_property PACKAGE_PIN K18 [get_ports {clk_120m_dac}] +set_property IOSTANDARD LVCMOS33 [get_ports {clk_120m_dac}] +create_clock -name clk_120m_dac -period 8.333 [get_ports {clk_120m_dac}] +set_input_jitter [get_clocks clk_120m_dac] 0.100 + +# -------------------------------------------------------------------------- +# FT601 Clock Input — 100 MHz from FT601 chip, Bank 16 MRCC +# Pin: D17 = IO_L12P_T1_MRCC_16 +# -------------------------------------------------------------------------- +set_property PACKAGE_PIN D17 [get_ports {ft601_clk_in}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_clk_in}] +create_clock -name ft601_clk_in -period 10.000 [get_ports {ft601_clk_in}] +set_input_jitter [get_clocks ft601_clk_in] 0.100 + +# -------------------------------------------------------------------------- +# ADC DCO Clock — 400 MHz LVDS from AD9484, Bank 14 MRCC +# Pins: W19/W20 = IO_L12P_T1_MRCC_14 / IO_L12N_T1_MRCC_14 +# -------------------------------------------------------------------------- +set_property PACKAGE_PIN W19 [get_ports {adc_dco_p}] +set_property PACKAGE_PIN W20 [get_ports {adc_dco_n}] +set_property IOSTANDARD LVDS_25 [get_ports {adc_dco_p}] +set_property IOSTANDARD LVDS_25 [get_ports {adc_dco_n}] +set_property DIFF_TERM TRUE [get_ports {adc_dco_p}] +create_clock -name adc_dco_p -period 2.500 [get_ports {adc_dco_p}] +set_input_jitter [get_clocks adc_dco_p] 0.050 + +# ============================================================================ +# RESET (Active-Low) — Bank 15, VCCO = 3.3V +# ============================================================================ +# Pin: J16 = IO_0_15 (standalone, not part of a diff pair) +set_property PACKAGE_PIN J16 [get_ports {reset_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {reset_n}] +set_property PULLUP true [get_ports {reset_n}] + +# ============================================================================ +# ADC INTERFACE — Bank 14, VCCO = 2.5V, LVDS_25 with DIFF_TERM +# ============================================================================ +# AD9484 8-bit LVDS data pairs. Each pair uses matched P/N pins in Bank 14. +# LVDS_25 with internal differential termination provides better signal +# integrity than LVDS_33 used on the upstream board. + +# adc_d[0]: IO_L1P/L1N_T0_D00/D01_14 +set_property PACKAGE_PIN P22 [get_ports {adc_d_p[0]}] +set_property PACKAGE_PIN R22 [get_ports {adc_d_n[0]}] +# adc_d[1]: IO_L2P/L2N_T0_D02/D03_14 +set_property PACKAGE_PIN P21 [get_ports {adc_d_p[1]}] +set_property PACKAGE_PIN R21 [get_ports {adc_d_n[1]}] +# adc_d[2]: IO_L3P/L3N_T0_DQS_14 +set_property PACKAGE_PIN U22 [get_ports {adc_d_p[2]}] +set_property PACKAGE_PIN V22 [get_ports {adc_d_n[2]}] +# adc_d[3]: IO_L4P/L4N_T0_D04/D05_14 +set_property PACKAGE_PIN T21 [get_ports {adc_d_p[3]}] +set_property PACKAGE_PIN U21 [get_ports {adc_d_n[3]}] +# adc_d[4]: IO_L5P/L5N_T0_D06/D07_14 +set_property PACKAGE_PIN P19 [get_ports {adc_d_p[4]}] +set_property PACKAGE_PIN R19 [get_ports {adc_d_n[4]}] +# adc_d[5]: IO_L7P/L7N_T1_D09/D10_14 +set_property PACKAGE_PIN W21 [get_ports {adc_d_p[5]}] +set_property PACKAGE_PIN W22 [get_ports {adc_d_n[5]}] +# adc_d[6]: IO_L8P/L8N_T1_D11/D12_14 +set_property PACKAGE_PIN AA20 [get_ports {adc_d_p[6]}] +set_property PACKAGE_PIN AA21 [get_ports {adc_d_n[6]}] +# adc_d[7]: IO_L9P/L9N_T1_DQS_D13_14 +set_property PACKAGE_PIN Y21 [get_ports {adc_d_p[7]}] +set_property PACKAGE_PIN Y22 [get_ports {adc_d_n[7]}] + +# LVDS I/O standard and differential termination +set_property IOSTANDARD LVDS_25 [get_ports {adc_d_p[*]}] +set_property IOSTANDARD LVDS_25 [get_ports {adc_d_n[*]}] +set_property DIFF_TERM TRUE [get_ports {adc_d_p[*]}] + +# ADC Power Down — single-ended, Bank 14 (LVCMOS25 matches bank VCCO) +# Pin: P20 = IO_0_14 +set_property PACKAGE_PIN P20 [get_ports {adc_pwdn}] +set_property IOSTANDARD LVCMOS25 [get_ports {adc_pwdn}] + +# ============================================================================ +# TRANSMITTER INTERFACE — DAC (Bank 15, VCCO = 3.3V) +# ============================================================================ + +# DAC Data Bus (8-bit) — AD9708 data inputs +# Using Bank 15 L1..L6 pins (single-ended from diff pairs) +set_property PACKAGE_PIN H13 [get_ports {dac_data[0]}] +set_property PACKAGE_PIN G13 [get_ports {dac_data[1]}] +set_property PACKAGE_PIN G15 [get_ports {dac_data[2]}] +set_property PACKAGE_PIN G16 [get_ports {dac_data[3]}] +set_property PACKAGE_PIN G17 [get_ports {dac_data[4]}] +set_property PACKAGE_PIN G18 [get_ports {dac_data[5]}] +set_property PACKAGE_PIN J15 [get_ports {dac_data[6]}] +set_property PACKAGE_PIN H15 [get_ports {dac_data[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {dac_data[*]}] +set_property SLEW FAST [get_ports {dac_data[*]}] +set_property DRIVE 8 [get_ports {dac_data[*]}] + +# DAC Clock Output — FPGA drives DAC clock on production board +# (On upstream board, DAC clock came from AD9523 directly; not routed to FPGA) +# Pin: H17 = IO_L6P_T0_15 +set_property PACKAGE_PIN H17 [get_ports {dac_clk}] +set_property IOSTANDARD LVCMOS33 [get_ports {dac_clk}] +set_property SLEW FAST [get_ports {dac_clk}] +set_property DRIVE 8 [get_ports {dac_clk}] + +# DAC Sleep Control +# Pin: H18 = IO_L6N_T0_VREF_15 +set_property PACKAGE_PIN H18 [get_ports {dac_sleep}] +set_property IOSTANDARD LVCMOS33 [get_ports {dac_sleep}] + +# ============================================================================ +# RF SWITCH & MIXER CONTROL (Bank 15, VCCO = 3.3V) +# ============================================================================ +# Pin: J22 = IO_L7P_T1_AD2P_15 +set_property PACKAGE_PIN J22 [get_ports {fpga_rf_switch}] +set_property IOSTANDARD LVCMOS33 [get_ports {fpga_rf_switch}] + +# Pin: H22 = IO_L7N_T1_AD2N_15 +set_property PACKAGE_PIN H22 [get_ports {rx_mixer_en}] +set_property IOSTANDARD LVCMOS33 [get_ports {rx_mixer_en}] + +# Pin: H20 = IO_L8P_T1_AD10P_15 +set_property PACKAGE_PIN H20 [get_ports {tx_mixer_en}] +set_property IOSTANDARD LVCMOS33 [get_ports {tx_mixer_en}] + +# ============================================================================ +# LEVEL SHIFTER SPI — 3.3V side from STM32 (Bank 15, VCCO = 3.3V) +# ============================================================================ +# Pin: K21 = IO_L9P_T1_DQS_AD3P_15 +set_property PACKAGE_PIN K21 [get_ports {stm32_sclk_3v3}] +# Pin: K22 = IO_L9N_T1_DQS_AD3N_15 +set_property PACKAGE_PIN K22 [get_ports {stm32_mosi_3v3}] +# Pin: M21 = IO_L10P_T1_AD11P_15 +set_property PACKAGE_PIN M21 [get_ports {stm32_miso_3v3}] +# Pin: L21 = IO_L10N_T1_AD11N_15 +set_property PACKAGE_PIN L21 [get_ports {stm32_cs_adar1_3v3}] +# Pin: N22 = IO_L15P_T2_DQS_15 +set_property PACKAGE_PIN N22 [get_ports {stm32_cs_adar2_3v3}] +# Pin: M22 = IO_L15N_T2_DQS_ADV_B_15 +set_property PACKAGE_PIN M22 [get_ports {stm32_cs_adar3_3v3}] +# Pin: M18 = IO_L16P_T2_A28_15 +set_property PACKAGE_PIN M18 [get_ports {stm32_cs_adar4_3v3}] +set_property IOSTANDARD LVCMOS33 [get_ports {stm32_*_3v3}] + +# ============================================================================ +# STM32 DIG BUS — Control signals (Bank 15, VCCO = 3.3V) +# ============================================================================ +# Pin: L18 = IO_L16N_T2_A27_15 +set_property PACKAGE_PIN L18 [get_ports {stm32_new_chirp}] +# Pin: N18 = IO_L17P_T2_A26_15 +set_property PACKAGE_PIN N18 [get_ports {stm32_new_elevation}] +# Pin: N19 = IO_L17N_T2_A25_15 +set_property PACKAGE_PIN N19 [get_ports {stm32_new_azimuth}] +# Pin: N20 = IO_L18P_T2_A24_15 +set_property PACKAGE_PIN N20 [get_ports {stm32_mixers_enable}] +set_property IOSTANDARD LVCMOS33 [get_ports {stm32_new_*}] +set_property IOSTANDARD LVCMOS33 [get_ports {stm32_mixers_enable}] + +# ============================================================================ +# ADAR1000 BEAMFORMER CONTROL (Bank 34, VCCO = 1.8V) +# ============================================================================ + +# TX Load Pins — active-high pulse via level shifters +# Pin: T1 = IO_L1P_T0_34 +set_property PACKAGE_PIN T1 [get_ports {adar_tx_load_1}] +# Pin: U1 = IO_L1N_T0_34 +set_property PACKAGE_PIN U1 [get_ports {adar_tx_load_2}] +# Pin: U2 = IO_L2P_T0_34 +set_property PACKAGE_PIN U2 [get_ports {adar_tx_load_3}] +# Pin: V2 = IO_L2N_T0_34 +set_property PACKAGE_PIN V2 [get_ports {adar_tx_load_4}] + +# RX Load Pins +# Pin: W2 = IO_L4P_T0_34 +set_property PACKAGE_PIN W2 [get_ports {adar_rx_load_1}] +# Pin: Y2 = IO_L4N_T0_34 +set_property PACKAGE_PIN Y2 [get_ports {adar_rx_load_2}] +# Pin: W1 = IO_L5P_T0_34 +set_property PACKAGE_PIN W1 [get_ports {adar_rx_load_3}] +# Pin: Y1 = IO_L5N_T0_34 +set_property PACKAGE_PIN Y1 [get_ports {adar_rx_load_4}] + +set_property IOSTANDARD LVCMOS18 [get_ports {adar_*_load_*}] + +# TR (Transmit/Receive) Pins +# Pin: AA1 = IO_L7P_T1_34 +set_property PACKAGE_PIN AA1 [get_ports {adar_tr_1}] +# Pin: AB1 = IO_L7N_T1_34 +set_property PACKAGE_PIN AB1 [get_ports {adar_tr_2}] +# Pin: AB3 = IO_L8P_T1_34 +set_property PACKAGE_PIN AB3 [get_ports {adar_tr_3}] +# Pin: AB2 = IO_L8N_T1_34 +set_property PACKAGE_PIN AB2 [get_ports {adar_tr_4}] +set_property IOSTANDARD LVCMOS18 [get_ports {adar_tr_*}] + +# ============================================================================ +# LEVEL SHIFTER SPI — 1.8V side to ADAR1000 (Bank 34, VCCO = 1.8V) +# ============================================================================ +# Pin: Y3 = IO_L9P_T1_DQS_34 +set_property PACKAGE_PIN Y3 [get_ports {stm32_sclk_1v8}] +# Pin: AA3 = IO_L9N_T1_DQS_34 +set_property PACKAGE_PIN AA3 [get_ports {stm32_mosi_1v8}] +# Pin: AA5 = IO_L10P_T1_34 +set_property PACKAGE_PIN AA5 [get_ports {stm32_miso_1v8}] +# Pin: AB5 = IO_L10N_T1_34 +set_property PACKAGE_PIN AB5 [get_ports {stm32_cs_adar1_1v8}] +# Pin: W6 = IO_L15P_T2_DQS_34 +set_property PACKAGE_PIN W6 [get_ports {stm32_cs_adar2_1v8}] +# Pin: W5 = IO_L15N_T2_DQS_34 +set_property PACKAGE_PIN W5 [get_ports {stm32_cs_adar3_1v8}] +# Pin: U6 = IO_L16P_T2_34 +set_property PACKAGE_PIN U6 [get_ports {stm32_cs_adar4_1v8}] +set_property IOSTANDARD LVCMOS18 [get_ports {stm32_*_1v8}] + +# ============================================================================ +# FT601 USB 3.0 INTERFACE (Bank 16, VCCO = 3.3V) +# ============================================================================ +# FT601 is fully wired on the production board. +# 32-bit data bus + 4-bit byte enable + control signals. +# +# NOTE: Current RTL declares ft601_be[1:0]. Production board requires +# ft601_be[3:0] for 32-bit FT601 mode. RTL update needed. + +# --- ft601_clk_in on MRCC (D17) constrained above in CLOCK section --- + +# FT601 Clock Output (forwarded clock to FT601) +# Pin: C17 = IO_L12N_T1_MRCC_16 (paired with clk_in on L12P) +set_property PACKAGE_PIN C17 [get_ports {ft601_clk_out}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_clk_out}] +set_property SLEW FAST [get_ports {ft601_clk_out}] +set_property DRIVE 8 [get_ports {ft601_clk_out}] + +# FT601 Data Bus [31:0] — bidirectional, 3.3V LVCMOS +set_property PACKAGE_PIN F13 [get_ports {ft601_data[0]}] +set_property PACKAGE_PIN F14 [get_ports {ft601_data[1]}] +set_property PACKAGE_PIN F16 [get_ports {ft601_data[2]}] +set_property PACKAGE_PIN E17 [get_ports {ft601_data[3]}] +set_property PACKAGE_PIN C14 [get_ports {ft601_data[4]}] +set_property PACKAGE_PIN C15 [get_ports {ft601_data[5]}] +set_property PACKAGE_PIN E13 [get_ports {ft601_data[6]}] +set_property PACKAGE_PIN E14 [get_ports {ft601_data[7]}] +set_property PACKAGE_PIN E16 [get_ports {ft601_data[8]}] +set_property PACKAGE_PIN D16 [get_ports {ft601_data[9]}] +set_property PACKAGE_PIN D14 [get_ports {ft601_data[10]}] +set_property PACKAGE_PIN D15 [get_ports {ft601_data[11]}] +set_property PACKAGE_PIN B15 [get_ports {ft601_data[12]}] +set_property PACKAGE_PIN B16 [get_ports {ft601_data[13]}] +set_property PACKAGE_PIN C13 [get_ports {ft601_data[14]}] +set_property PACKAGE_PIN B13 [get_ports {ft601_data[15]}] +set_property PACKAGE_PIN A15 [get_ports {ft601_data[16]}] +set_property PACKAGE_PIN A16 [get_ports {ft601_data[17]}] +set_property PACKAGE_PIN A13 [get_ports {ft601_data[18]}] +set_property PACKAGE_PIN A14 [get_ports {ft601_data[19]}] +set_property PACKAGE_PIN B17 [get_ports {ft601_data[20]}] +set_property PACKAGE_PIN B18 [get_ports {ft601_data[21]}] +set_property PACKAGE_PIN F18 [get_ports {ft601_data[22]}] +set_property PACKAGE_PIN E18 [get_ports {ft601_data[23]}] +set_property PACKAGE_PIN B20 [get_ports {ft601_data[24]}] +set_property PACKAGE_PIN A20 [get_ports {ft601_data[25]}] +set_property PACKAGE_PIN A18 [get_ports {ft601_data[26]}] +set_property PACKAGE_PIN A19 [get_ports {ft601_data[27]}] +set_property PACKAGE_PIN F19 [get_ports {ft601_data[28]}] +set_property PACKAGE_PIN F20 [get_ports {ft601_data[29]}] +set_property PACKAGE_PIN D20 [get_ports {ft601_data[30]}] +set_property PACKAGE_PIN C20 [get_ports {ft601_data[31]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_data[*]}] +set_property SLEW FAST [get_ports {ft601_data[*]}] +set_property DRIVE 8 [get_ports {ft601_data[*]}] + +# FT601 Byte Enable [3:0] +set_property PACKAGE_PIN C22 [get_ports {ft601_be[0]}] +set_property PACKAGE_PIN B22 [get_ports {ft601_be[1]}] +set_property PACKAGE_PIN B21 [get_ports {ft601_be[2]}] +set_property PACKAGE_PIN A21 [get_ports {ft601_be[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_be[*]}] +set_property SLEW FAST [get_ports {ft601_be[*]}] +set_property DRIVE 8 [get_ports {ft601_be[*]}] + +# FT601 Control Signals — active-low strobes +set_property PACKAGE_PIN E22 [get_ports {ft601_wr_n}] +set_property PACKAGE_PIN D22 [get_ports {ft601_rd_n}] +set_property PACKAGE_PIN E21 [get_ports {ft601_oe_n}] +set_property PACKAGE_PIN D21 [get_ports {ft601_siwu_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_wr_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_rd_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_oe_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_siwu_n}] +set_property SLEW FAST [get_ports {ft601_wr_n}] +set_property SLEW FAST [get_ports {ft601_rd_n}] +set_property SLEW FAST [get_ports {ft601_oe_n}] +set_property DRIVE 8 [get_ports {ft601_wr_n}] +set_property DRIVE 8 [get_ports {ft601_rd_n}] +set_property DRIVE 8 [get_ports {ft601_oe_n}] + +# FT601 active-low enable outputs (directly from FPGA to FT601) +set_property PACKAGE_PIN G21 [get_ports {ft601_txe_n}] +set_property PACKAGE_PIN G22 [get_ports {ft601_rxf_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_txe_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_rxf_n}] + +# FT601 status inputs (active-high from FT601 to FPGA) +set_property PACKAGE_PIN F21 [get_ports {ft601_txe}] +set_property PACKAGE_PIN F15 [get_ports {ft601_rxf}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_txe}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_rxf}] + +# FT601 FIFO buffer select inputs +set_property PACKAGE_PIN C18 [get_ports {ft601_srb[0]}] +set_property PACKAGE_PIN C19 [get_ports {ft601_srb[1]}] +set_property PACKAGE_PIN E19 [get_ports {ft601_swb[0]}] +set_property PACKAGE_PIN D19 [get_ports {ft601_swb[1]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_srb[*]}] +set_property IOSTANDARD LVCMOS33 [get_ports {ft601_swb[*]}] + +# ============================================================================ +# STATUS OUTPUTS — Beam Position & System Status (Bank 35, VCCO = 3.3V) +# ============================================================================ + +# current_elevation[5:0] +set_property PACKAGE_PIN B1 [get_ports {current_elevation[0]}] +set_property PACKAGE_PIN A1 [get_ports {current_elevation[1]}] +set_property PACKAGE_PIN C2 [get_ports {current_elevation[2]}] +set_property PACKAGE_PIN B2 [get_ports {current_elevation[3]}] +set_property PACKAGE_PIN E1 [get_ports {current_elevation[4]}] +set_property PACKAGE_PIN D1 [get_ports {current_elevation[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {current_elevation[*]}] + +# current_azimuth[5:0] +set_property PACKAGE_PIN E2 [get_ports {current_azimuth[0]}] +set_property PACKAGE_PIN D2 [get_ports {current_azimuth[1]}] +set_property PACKAGE_PIN G1 [get_ports {current_azimuth[2]}] +set_property PACKAGE_PIN F1 [get_ports {current_azimuth[3]}] +set_property PACKAGE_PIN F3 [get_ports {current_azimuth[4]}] +set_property PACKAGE_PIN E3 [get_ports {current_azimuth[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {current_azimuth[*]}] + +# current_chirp[5:0] +set_property PACKAGE_PIN K1 [get_ports {current_chirp[0]}] +set_property PACKAGE_PIN J1 [get_ports {current_chirp[1]}] +set_property PACKAGE_PIN H2 [get_ports {current_chirp[2]}] +set_property PACKAGE_PIN G2 [get_ports {current_chirp[3]}] +set_property PACKAGE_PIN K2 [get_ports {current_chirp[4]}] +set_property PACKAGE_PIN J2 [get_ports {current_chirp[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {current_chirp[*]}] + +# new_chirp_frame +set_property PACKAGE_PIN J5 [get_ports {new_chirp_frame}] +set_property IOSTANDARD LVCMOS33 [get_ports {new_chirp_frame}] + +# system_status[3:0] +set_property PACKAGE_PIN H5 [get_ports {system_status[0]}] +set_property PACKAGE_PIN H3 [get_ports {system_status[1]}] +set_property PACKAGE_PIN G3 [get_ports {system_status[2]}] +set_property PACKAGE_PIN H4 [get_ports {system_status[3]}] +set_property IOSTANDARD LVCMOS33 [get_ports {system_status[*]}] + +# ============================================================================ +# DEBUG OUTPUTS — Doppler Data (Bank 35, VCCO = 3.3V) +# ============================================================================ +# dbg_doppler_data[26:0] on Bank 35, dbg_doppler_data[31:27] on Bank 13 + +# dbg_doppler_data[26:0] — Bank 35 +set_property PACKAGE_PIN G4 [get_ports {dbg_doppler_data[0]}] +set_property PACKAGE_PIN K4 [get_ports {dbg_doppler_data[1]}] +set_property PACKAGE_PIN J4 [get_ports {dbg_doppler_data[2]}] +set_property PACKAGE_PIN L3 [get_ports {dbg_doppler_data[3]}] +set_property PACKAGE_PIN K3 [get_ports {dbg_doppler_data[4]}] +set_property PACKAGE_PIN M1 [get_ports {dbg_doppler_data[5]}] +set_property PACKAGE_PIN L1 [get_ports {dbg_doppler_data[6]}] +set_property PACKAGE_PIN M3 [get_ports {dbg_doppler_data[7]}] +set_property PACKAGE_PIN M2 [get_ports {dbg_doppler_data[8]}] +set_property PACKAGE_PIN K6 [get_ports {dbg_doppler_data[9]}] +set_property PACKAGE_PIN J6 [get_ports {dbg_doppler_data[10]}] +set_property PACKAGE_PIN L5 [get_ports {dbg_doppler_data[11]}] +set_property PACKAGE_PIN L4 [get_ports {dbg_doppler_data[12]}] +set_property PACKAGE_PIN N4 [get_ports {dbg_doppler_data[13]}] +set_property PACKAGE_PIN N3 [get_ports {dbg_doppler_data[14]}] +set_property PACKAGE_PIN R1 [get_ports {dbg_doppler_data[15]}] +set_property PACKAGE_PIN P1 [get_ports {dbg_doppler_data[16]}] +set_property PACKAGE_PIN P5 [get_ports {dbg_doppler_data[17]}] +set_property PACKAGE_PIN P4 [get_ports {dbg_doppler_data[18]}] +set_property PACKAGE_PIN P2 [get_ports {dbg_doppler_data[19]}] +set_property PACKAGE_PIN N2 [get_ports {dbg_doppler_data[20]}] +set_property PACKAGE_PIN M6 [get_ports {dbg_doppler_data[21]}] +set_property PACKAGE_PIN M5 [get_ports {dbg_doppler_data[22]}] +set_property PACKAGE_PIN P6 [get_ports {dbg_doppler_data[23]}] +set_property PACKAGE_PIN N5 [get_ports {dbg_doppler_data[24]}] +set_property PACKAGE_PIN L6 [get_ports {dbg_doppler_data[25]}] +set_property PACKAGE_PIN F4 [get_ports {dbg_doppler_data[26]}] + +# dbg_doppler_data[31:27] — Bank 13 (overflow) +set_property PACKAGE_PIN Y17 [get_ports {dbg_doppler_data[27]}] +set_property PACKAGE_PIN Y16 [get_ports {dbg_doppler_data[28]}] +set_property PACKAGE_PIN AA16 [get_ports {dbg_doppler_data[29]}] +set_property PACKAGE_PIN AB16 [get_ports {dbg_doppler_data[30]}] +set_property PACKAGE_PIN AB17 [get_ports {dbg_doppler_data[31]}] + +set_property IOSTANDARD LVCMOS33 [get_ports {dbg_doppler_data[*]}] + +# ============================================================================ +# DEBUG OUTPUTS — Doppler Valid & Bins (Bank 13, VCCO = 3.3V) +# ============================================================================ + +set_property PACKAGE_PIN AA13 [get_ports {dbg_doppler_valid}] +set_property IOSTANDARD LVCMOS33 [get_ports {dbg_doppler_valid}] + +# dbg_doppler_bin[4:0] +set_property PACKAGE_PIN AB13 [get_ports {dbg_doppler_bin[0]}] +set_property PACKAGE_PIN AA15 [get_ports {dbg_doppler_bin[1]}] +set_property PACKAGE_PIN AB15 [get_ports {dbg_doppler_bin[2]}] +set_property PACKAGE_PIN Y13 [get_ports {dbg_doppler_bin[3]}] +set_property PACKAGE_PIN AA14 [get_ports {dbg_doppler_bin[4]}] +set_property IOSTANDARD LVCMOS33 [get_ports {dbg_doppler_bin[*]}] + +# dbg_range_bin[5:0] +set_property PACKAGE_PIN W14 [get_ports {dbg_range_bin[0]}] +set_property PACKAGE_PIN Y14 [get_ports {dbg_range_bin[1]}] +set_property PACKAGE_PIN AB11 [get_ports {dbg_range_bin[2]}] +set_property PACKAGE_PIN AB12 [get_ports {dbg_range_bin[3]}] +set_property PACKAGE_PIN AA9 [get_ports {dbg_range_bin[4]}] +set_property PACKAGE_PIN AB10 [get_ports {dbg_range_bin[5]}] +set_property IOSTANDARD LVCMOS33 [get_ports {dbg_range_bin[*]}] + +# ============================================================================ +# INPUT DELAY CONSTRAINTS +# ============================================================================ + +# ADC data relative to DCO (source-synchronous, center-aligned) +# NOTE: Rising-edge input delay constraints are here; falling-edge + BUFIO +# adjustments are in the "ADC SOURCE-SYNCHRONOUS INPUT CONSTRAINTS" section below. +# DDR at 400 MHz → 2.5 ns period, data valid window ±0.625 ns +# These are overridden by the more complete constraints below (with -add_delay +# for clock_fall), but kept for documentation of the original intent. +# set_input_delay -clock [get_clocks adc_dco_p] -max 1.000 [get_ports {adc_d_p[*]}] +# set_input_delay -clock [get_clocks adc_dco_p] -min 0.200 [get_ports {adc_d_p[*]}] + +# FT601 input delays (relative to ft601_clk_in, 100 MHz) +# FT601 datasheet: Tco max = 7.0 ns, Tco min = 1.0 ns +set_input_delay -clock [get_clocks ft601_clk_in] -max 7.000 [get_ports {ft601_data[*]}] +set_input_delay -clock [get_clocks ft601_clk_in] -min 1.000 [get_ports {ft601_data[*]}] +set_input_delay -clock [get_clocks ft601_clk_in] -max 7.000 [get_ports {ft601_txe}] +set_input_delay -clock [get_clocks ft601_clk_in] -min 1.000 [get_ports {ft601_txe}] +set_input_delay -clock [get_clocks ft601_clk_in] -max 7.000 [get_ports {ft601_rxf}] +set_input_delay -clock [get_clocks ft601_clk_in] -min 1.000 [get_ports {ft601_rxf}] +set_input_delay -clock [get_clocks ft601_clk_in] -max 7.000 [get_ports {ft601_srb[*]}] +set_input_delay -clock [get_clocks ft601_clk_in] -min 1.000 [get_ports {ft601_srb[*]}] +set_input_delay -clock [get_clocks ft601_clk_in] -max 7.000 [get_ports {ft601_swb[*]}] +set_input_delay -clock [get_clocks ft601_clk_in] -min 1.000 [get_ports {ft601_swb[*]}] + +# ============================================================================ +# OUTPUT DELAY CONSTRAINTS +# ============================================================================ + +# -------------------------------------------------------------------------- +# DAC output delay relative to ODDR-forwarded clock +# -------------------------------------------------------------------------- +# dac_clk is now forwarded via ODDR from clk_120m_dac BUFG output. +# Create a generated clock on the dac_clk output pin representing the +# ODDR-forwarded clock. Output delays are then set relative to THIS +# generated clock, not the source port clock. Since both data ODDRs and +# clock ODDR are driven by the same BUFG, insertion delays cancel. +# +# AD9708 specs at the DAC pin: Tsu = 2.0 ns, Th = 1.5 ns +# Board trace skew budget: ~0.5 ns (conservative) +# output_delay_max = Tsu + trace_skew = 2.0 + 0.5 = 2.5 ns +# output_delay_min = -(Th - trace_skew) = -(1.5 - 0.5) = -1.0 ns +create_generated_clock -name dac_clk_fwd \ + -source [get_pins -hierarchical -filter {NAME =~ *oddr_dac_clk/C}] \ + -divide_by 1 \ + [get_ports {dac_clk}] + +set_output_delay -clock [get_clocks dac_clk_fwd] -max 2.500 [get_ports {dac_data[*]}] +set_output_delay -clock [get_clocks dac_clk_fwd] -min -1.000 [get_ports {dac_data[*]}] + +# dac_clk itself has no meaningful output delay (it IS the clock reference) +# but we remove the old constraint that was relative to the source port clock. + +# -------------------------------------------------------------------------- +# FT601 output delay relative to ODDR-forwarded clock +# -------------------------------------------------------------------------- +# ft601_clk_out is now forwarded via ODDR from ft601_clk_in BUFG output. +# Since both data FFs and clock ODDR are driven by the same BUFG, insertion +# delays cancel. Output delay only needs to cover FT601 Tsu/Th + trace skew. +# +# FT601 specs: Tsu = 3.0 ns, Th = 0.5 ns +# Board trace skew budget: ~0.5 ns +# output_delay_max = Tsu + trace_skew = 3.0 + 0.5 = 3.5 ns +# output_delay_min = -(Th - trace_skew) = -(0.5 - 0.5) = 0.0 ns +create_generated_clock -name ft601_clk_fwd \ + -source [get_pins -hierarchical -filter {NAME =~ *oddr_ft601_clk/C}] \ + -divide_by 1 \ + [get_ports {ft601_clk_out}] + +set_output_delay -clock [get_clocks ft601_clk_fwd] -max 3.500 [get_ports {ft601_data[*]}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -min 0.000 [get_ports {ft601_data[*]}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -max 3.500 [get_ports {ft601_be[*]}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -min 0.000 [get_ports {ft601_be[*]}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -max 3.500 [get_ports {ft601_wr_n}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -min 0.000 [get_ports {ft601_wr_n}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -max 3.500 [get_ports {ft601_rd_n}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -min 0.000 [get_ports {ft601_rd_n}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -max 3.500 [get_ports {ft601_oe_n}] +set_output_delay -clock [get_clocks ft601_clk_fwd] -min 0.000 [get_ports {ft601_oe_n}] + +# ============================================================================ +# TIMING EXCEPTIONS — FALSE PATHS +# ============================================================================ + +# Asynchronous STM32 control signals (toggle interface, double-synced in RTL) +set_false_path -from [get_ports {stm32_new_*}] +set_false_path -from [get_ports {stm32_mixers_enable}] + +# Async reset false paths +# reset_n is held asserted for many clock cycles. All paths originating from +# the reset port or reset synchronizer registers are false paths — this covers +# both data paths (setup/hold) and asynchronous control paths (recovery/removal). +# +# NOTE: Using -from only (no -to filter). Vivado does not accept CLR/PRE pins +# as valid endpoints for set_false_path -to. Waiving all paths FROM these +# sources is the correct and standard approach. +set_false_path -from [get_ports {reset_n}] +set_false_path -from [get_cells -hierarchical -filter {NAME =~ *reset_sync*}] + +# ============================================================================ +# TIMING EXCEPTIONS — CLOCK DOMAIN CROSSINGS +# ============================================================================ + +# clk_100m ↔ adc_dco_p (400 MHz): DDC has internal CDC synchronizers +set_false_path -from [get_clocks clk_100m] -to [get_clocks adc_dco_p] +set_false_path -from [get_clocks adc_dco_p] -to [get_clocks clk_100m] + +# clk_100m ↔ clk_120m_dac: CDC via synchronizers in radar_system_top +set_false_path -from [get_clocks clk_100m] -to [get_clocks clk_120m_dac] +set_false_path -from [get_clocks clk_120m_dac] -to [get_clocks clk_100m] + +# clk_100m ↔ ft601_clk_in: USB data interface has CDC synchronizers +set_false_path -from [get_clocks clk_100m] -to [get_clocks ft601_clk_in] +set_false_path -from [get_clocks ft601_clk_in] -to [get_clocks clk_100m] + +# clk_120m_dac ↔ ft601_clk_in: no direct data path expected +set_false_path -from [get_clocks clk_120m_dac] -to [get_clocks ft601_clk_in] +set_false_path -from [get_clocks ft601_clk_in] -to [get_clocks clk_120m_dac] + +# adc_dco_p ↔ ft601_clk_in: no direct data path expected +set_false_path -from [get_clocks adc_dco_p] -to [get_clocks ft601_clk_in] +set_false_path -from [get_clocks ft601_clk_in] -to [get_clocks adc_dco_p] + +# Generated clock cross-domain paths: +# dac_clk_fwd and ft601_clk_fwd are generated from their respective source +# clocks. Vivado automatically inherits the source clock false paths for +# generated clocks, but be explicit for clarity: +set_false_path -from [get_clocks clk_100m] -to [get_clocks dac_clk_fwd] +set_false_path -from [get_clocks dac_clk_fwd] -to [get_clocks clk_100m] +set_false_path -from [get_clocks ft601_clk_fwd] -to [get_clocks clk_120m_dac] +set_false_path -from [get_clocks clk_120m_dac] -to [get_clocks ft601_clk_fwd] + +# ============================================================================ +# ADC SOURCE-SYNCHRONOUS INPUT CONSTRAINTS +# ============================================================================ +# With BUFIO clocking the IDDR (near-zero insertion delay), the input delay +# constraints need updating. The IDDR sees data and clock with similar +# propagation delays (both through IOB primitives). +# +# AD9484 source-synchronous interface: +# - DDR at 400 MHz → 1.25 ns half-period (data valid window) +# - Data is center-aligned to DCO by the ADC +# - Tco_max (data after clock edge) = 1.0 ns, Tco_min = 0.2 ns +# +# With BUFIO, the clock insertion delay at IDDR is ~0.3 ns (vs 4.4 ns BUFG). +# Input delay values are board-level delays only. +set_input_delay -clock [get_clocks adc_dco_p] -max 1.000 [get_ports {adc_d_p[*]}] +set_input_delay -clock [get_clocks adc_dco_p] -min 0.200 [get_ports {adc_d_p[*]}] +# DDR falling edge captures +set_input_delay -clock [get_clocks adc_dco_p] -max 1.000 -clock_fall [get_ports {adc_d_p[*]}] -add_delay +set_input_delay -clock [get_clocks adc_dco_p] -min 0.200 -clock_fall [get_ports {adc_d_p[*]}] -add_delay + +# ============================================================================ +# IOB PACKING +# ============================================================================ +# Force DAC data and clock ODDR outputs into IOBs +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *oddr_dac_clk*}] +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *oddr_dac_data*}] +# Force FT601 clock ODDR into IOB +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *oddr_ft601_clk*}] +# FT601 data/control output FFs: packed into IOBs where possible +# NOTE: IOB packing requires the register to be the ONLY driver of the output +# and have no other fanout. The FT601 FSM may prevent this for some signals. +# Vivado will warn if it cannot pack — that's OK, timing is still met via +# the generated clock (insertion delay cancellation). +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_data_out_reg*}] +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_be_reg*}] +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_wr_n_reg*}] +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_rd_n_reg*}] +set_property IOB TRUE [get_cells -hierarchical -filter {NAME =~ *usb_inst/ft601_oe_n_reg*}] + +# ============================================================================ +# TIMING EXCEPTIONS — CIC DECIMATOR MULTICYCLE PATHS +# ============================================================================ +# CIC integrator stages operate at input rate but only produce valid output +# at the decimated rate (every N cycles). The wide combinational paths have +# multiple clock cycles to settle. +set_multicycle_path 2 -setup \ + -from [get_cells -hierarchical -filter {NAME =~ *cic_decimator*/integrator_reg*}] \ + -to [get_cells -hierarchical -filter {NAME =~ *cic_decimator*/integrator_reg*}] +set_multicycle_path 1 -hold \ + -from [get_cells -hierarchical -filter {NAME =~ *cic_decimator*/integrator_reg*}] \ + -to [get_cells -hierarchical -filter {NAME =~ *cic_decimator*/integrator_reg*}] + +# ============================================================================ +# END OF CONSTRAINTS +# ============================================================================ diff --git a/9_Firmware/9_2_FPGA/constraints/xc7a50t_ftg256.xdc b/9_Firmware/9_2_FPGA/constraints/xc7a50t_ftg256.xdc new file mode 100644 index 0000000..cb16122 --- /dev/null +++ b/9_Firmware/9_2_FPGA/constraints/xc7a50t_ftg256.xdc @@ -0,0 +1,322 @@ +# ============================================================================ +# RADAR SYSTEM FPGA CONSTRAINTS +# ============================================================================ +# Device: XC7A50T-2FTG256I (FTG256 package) +# Board: AERIS-10 Phased Array Radar — Main Board +# Source: Pin assignments extracted from Eagle schematic (RADAR_Main_Board.sch) +# FPGA = U42 +# +# NOTE: The README and prior version of this file incorrectly referenced +# XC7A100TCSG324-1. The physical board uses XC7A50T in a 256-ball BGA +# (FTG256). All PACKAGE_PIN values below are FTG256 ball locations. +# +# I/O Bank Voltage Summary: +# Bank 0: VCCO = 3.3V (JTAG, flash CS) +# Bank 14: VCCO = 3.3V (ADC LVDS data, SPI flash) +# Bank 15: VCCO = 3.3V (DAC, clocks, STM32 SPI 3.3V side, DIG bus, mixer) +# Bank 34: VCCO = 1.8V (ADAR1000 beamformer control, SPI 1.8V side) +# Bank 35: VCCO = 3.3V (unused — no signal connections) +# ============================================================================ + +# ============================================================================ +# CLOCK CONSTRAINTS +# ============================================================================ + +# 100MHz System Clock (AD9523 OUT6 → FPGA_SYS_CLOCK → Bank 15 MRCC pin E12) +set_property PACKAGE_PIN E12 [get_ports {clk_100m}] +set_property IOSTANDARD LVCMOS33 [get_ports {clk_100m}] +create_clock -name clk_100m -period 10.0 [get_ports {clk_100m}] +set_input_jitter [get_clocks clk_100m] 0.1 + +# 120MHz DAC Clock (AD9523 OUT11 → FPGA_DAC_CLOCK → Bank 15 MRCC pin C13) +# NOTE: The physical DAC (U3, AD9708) receives its clock directly from the +# AD9523 via a separate net (DAC_CLOCK), NOT from the FPGA. The FPGA +# uses this clock input for internal DAC data timing only. The RTL port +# `dac_clk` is an output that assigns clk_120m directly — it has no +# separate physical pin on this board and should be removed from the +# RTL or left unconnected. +set_property PACKAGE_PIN C13 [get_ports {clk_120m_dac}] +set_property IOSTANDARD LVCMOS33 [get_ports {clk_120m_dac}] +create_clock -name clk_120m_dac -period 8.333 [get_ports {clk_120m_dac}] +set_input_jitter [get_clocks clk_120m_dac] 0.1 + +# ADC DCO Clock (400MHz LVDS — AD9523 OUT5 → AD9484 → FPGA, Bank 14 MRCC) +set_property PACKAGE_PIN N14 [get_ports {adc_dco_p}] +set_property PACKAGE_PIN P14 [get_ports {adc_dco_n}] +set_property IOSTANDARD LVDS_33 [get_ports {adc_dco_p}] +set_property IOSTANDARD LVDS_33 [get_ports {adc_dco_n}] +set_property DIFF_TERM TRUE [get_ports {adc_dco_p}] +create_clock -name adc_dco_p -period 2.5 [get_ports {adc_dco_p}] +set_input_jitter [get_clocks adc_dco_p] 0.05 + +# -------------------------------------------------------------------------- +# FT601 Clock — COMMENTED OUT: FT601 (U6) is placed in schematic but has +# zero net connections. No physical clock pin exists on this board. +# -------------------------------------------------------------------------- +# create_clock -name ft601_clk_in -period 10.0 [get_ports {ft601_clk_in}] +# set_input_jitter [get_clocks ft601_clk_in] 0.1 + +# ============================================================================ +# RESET (Active-Low) +# ============================================================================ +# DIG_4 (STM32 PD12 → FPGA Bank 15 pin E15) +# STM32 firmware uses HAL_GPIO_WritePin to assert/deassert FPGA reset. + +set_property PACKAGE_PIN E15 [get_ports {reset_n}] +set_property IOSTANDARD LVCMOS33 [get_ports {reset_n}] +set_property PULLUP true [get_ports {reset_n}] + +# ============================================================================ +# TRANSMITTER INTERFACE (DAC — Bank 15, VCCO=3.3V) +# ============================================================================ + +# DAC Data Bus (8-bit) — AD9708 data inputs via schematic nets DAC_0..DAC_7 +set_property PACKAGE_PIN A14 [get_ports {dac_data[0]}] +set_property PACKAGE_PIN A13 [get_ports {dac_data[1]}] +set_property PACKAGE_PIN A12 [get_ports {dac_data[2]}] +set_property PACKAGE_PIN B11 [get_ports {dac_data[3]}] +set_property PACKAGE_PIN B10 [get_ports {dac_data[4]}] +set_property PACKAGE_PIN A10 [get_ports {dac_data[5]}] +set_property PACKAGE_PIN A9 [get_ports {dac_data[6]}] +set_property PACKAGE_PIN A8 [get_ports {dac_data[7]}] +set_property IOSTANDARD LVCMOS33 [get_ports {dac_data[*]}] +set_property SLEW FAST [get_ports {dac_data[*]}] +set_property DRIVE 8 [get_ports {dac_data[*]}] + +# DAC Clock Output — NOT DIRECTLY WIRED TO DAC IN SCHEMATIC +# The DAC chip (U3) receives its clock from AD9523 via a separate net +# (DAC_CLOCK), not from the FPGA. The RTL `dac_clk` output has no +# physical pin. Comment out or remove from RTL. +# set_property PACKAGE_PIN ??? [get_ports {dac_clk}] +# set_property IOSTANDARD LVCMOS33 [get_ports {dac_clk}] +# set_property SLEW FAST [get_ports {dac_clk}] + +# DAC Sleep Control — DAC_SLEEP net +set_property PACKAGE_PIN A15 [get_ports {dac_sleep}] +set_property IOSTANDARD LVCMOS33 [get_ports {dac_sleep}] + +# RF Switch Control — M3S_VCTRL net +set_property PACKAGE_PIN G15 [get_ports {fpga_rf_switch}] +set_property IOSTANDARD LVCMOS33 [get_ports {fpga_rf_switch}] + +# Mixer Enables — MIX_RX_EN, MIX_TX_EN nets +set_property PACKAGE_PIN D11 [get_ports {rx_mixer_en}] +set_property PACKAGE_PIN C11 [get_ports {tx_mixer_en}] +set_property IOSTANDARD LVCMOS33 [get_ports {rx_mixer_en}] +set_property IOSTANDARD LVCMOS33 [get_ports {tx_mixer_en}] + +# ============================================================================ +# ADAR1000 BEAMFORMER CONTROL (Bank 34, VCCO=1.8V) +# ============================================================================ + +# ADAR1000 TX Load Pins (via level shifters, active-high pulse) +set_property PACKAGE_PIN P3 [get_ports {adar_tx_load_1}] +set_property PACKAGE_PIN T4 [get_ports {adar_tx_load_2}] +set_property PACKAGE_PIN R3 [get_ports {adar_tx_load_3}] +set_property PACKAGE_PIN R2 [get_ports {adar_tx_load_4}] + +# ADAR1000 RX Load Pins +set_property PACKAGE_PIN M5 [get_ports {adar_rx_load_1}] +set_property PACKAGE_PIN T2 [get_ports {adar_rx_load_2}] +set_property PACKAGE_PIN R1 [get_ports {adar_rx_load_3}] +set_property PACKAGE_PIN N4 [get_ports {adar_rx_load_4}] + +# Bank 34 VCCO = 1.8V → must use LVCMOS18 (not LVCMOS33) +set_property IOSTANDARD LVCMOS18 [get_ports {adar_*_load_*}] + +# ADAR1000 TR (Transmit/Receive) Pins +set_property PACKAGE_PIN N2 [get_ports {adar_tr_1}] +set_property PACKAGE_PIN N1 [get_ports {adar_tr_2}] +set_property PACKAGE_PIN P1 [get_ports {adar_tr_3}] +set_property PACKAGE_PIN P4 [get_ports {adar_tr_4}] +set_property IOSTANDARD LVCMOS18 [get_ports {adar_tr_*}] + +# ============================================================================ +# LEVEL SHIFTER SPI INTERFACE (STM32 ↔ ADAR1000) +# ============================================================================ + +# 3.3V Side (from STM32, Bank 15, VCCO=3.3V) +set_property PACKAGE_PIN J16 [get_ports {stm32_sclk_3v3}] +set_property PACKAGE_PIN H13 [get_ports {stm32_mosi_3v3}] +set_property PACKAGE_PIN G14 [get_ports {stm32_miso_3v3}] +set_property PACKAGE_PIN F14 [get_ports {stm32_cs_adar1_3v3}] +set_property PACKAGE_PIN H16 [get_ports {stm32_cs_adar2_3v3}] +set_property PACKAGE_PIN G16 [get_ports {stm32_cs_adar3_3v3}] +set_property PACKAGE_PIN J15 [get_ports {stm32_cs_adar4_3v3}] +set_property IOSTANDARD LVCMOS33 [get_ports {stm32_*_3v3}] + +# 1.8V Side (to ADAR1000, Bank 34, VCCO=1.8V) +set_property PACKAGE_PIN P5 [get_ports {stm32_sclk_1v8}] +set_property PACKAGE_PIN M1 [get_ports {stm32_mosi_1v8}] +set_property PACKAGE_PIN N3 [get_ports {stm32_miso_1v8}] +set_property PACKAGE_PIN L5 [get_ports {stm32_cs_adar1_1v8}] +set_property PACKAGE_PIN L4 [get_ports {stm32_cs_adar2_1v8}] +set_property PACKAGE_PIN M4 [get_ports {stm32_cs_adar3_1v8}] +set_property PACKAGE_PIN M2 [get_ports {stm32_cs_adar4_1v8}] +set_property IOSTANDARD LVCMOS18 [get_ports {stm32_*_1v8}] + +# ============================================================================ +# STM32 CONTROL INTERFACE (DIG bus, Bank 15, VCCO=3.3V) +# ============================================================================ +# DIG_0..DIG_4 are STM32 outputs (PD8-PD12) → FPGA inputs +# DIG_5..DIG_7 are STM32 inputs (PD13-PD15) ← FPGA outputs (unused in RTL) + +set_property PACKAGE_PIN F13 [get_ports {stm32_new_chirp}] ;# DIG_0 (PD8) +set_property PACKAGE_PIN E16 [get_ports {stm32_new_elevation}] ;# DIG_1 (PD9) +set_property PACKAGE_PIN D16 [get_ports {stm32_new_azimuth}] ;# DIG_2 (PD10) +set_property PACKAGE_PIN F15 [get_ports {stm32_mixers_enable}] ;# DIG_3 (PD11) +set_property IOSTANDARD LVCMOS33 [get_ports {stm32_new_*}] +set_property IOSTANDARD LVCMOS33 [get_ports {stm32_mixers_enable}] +# reset_n is DIG_4 (PD12) — constrained above in the RESET section + +# DIG_5 = H11, DIG_6 = G12, DIG_7 = H12 — available for FPGA→STM32 status +# Currently unused in RTL. Could be connected to status outputs if needed. + +# ============================================================================ +# ADC INTERFACE (LVDS — Bank 14, VCCO=3.3V) +# ============================================================================ + +# ADC Data (8-bit LVDS pairs from AD9484) +set_property PACKAGE_PIN P15 [get_ports {adc_d_p[0]}] +set_property PACKAGE_PIN P16 [get_ports {adc_d_n[0]}] +set_property PACKAGE_PIN R15 [get_ports {adc_d_p[1]}] +set_property PACKAGE_PIN R16 [get_ports {adc_d_n[1]}] +set_property PACKAGE_PIN T14 [get_ports {adc_d_p[2]}] +set_property PACKAGE_PIN T15 [get_ports {adc_d_n[2]}] +set_property PACKAGE_PIN R13 [get_ports {adc_d_p[3]}] +set_property PACKAGE_PIN T13 [get_ports {adc_d_n[3]}] +set_property PACKAGE_PIN R10 [get_ports {adc_d_p[4]}] +set_property PACKAGE_PIN R11 [get_ports {adc_d_n[4]}] +set_property PACKAGE_PIN T9 [get_ports {adc_d_p[5]}] +set_property PACKAGE_PIN T10 [get_ports {adc_d_n[5]}] +set_property PACKAGE_PIN T7 [get_ports {adc_d_p[6]}] +set_property PACKAGE_PIN T8 [get_ports {adc_d_n[6]}] +set_property PACKAGE_PIN R6 [get_ports {adc_d_p[7]}] +set_property PACKAGE_PIN R7 [get_ports {adc_d_n[7]}] + +# ADC DCO Clock (LVDS) — already constrained above in CLOCK section + +# ADC Power Down — ADC_PWRD net (single-ended, Bank 14) +set_property PACKAGE_PIN T5 [get_ports {adc_pwdn}] +set_property IOSTANDARD LVCMOS33 [get_ports {adc_pwdn}] + +# LVDS I/O Standard — Bank 14 VCCO = 3.3V → use LVDS_33 (not LVDS_25) +set_property IOSTANDARD LVDS_33 [get_ports {adc_d_p[*]}] +set_property IOSTANDARD LVDS_33 [get_ports {adc_d_n[*]}] + +# Differential termination +set_property DIFF_TERM TRUE [get_ports {adc_d_p[*]}] + +# Input delay for ADC data relative to DCO (adjust based on PCB trace length) +set_input_delay -clock [get_clocks adc_dco_p] -max 1.0 [get_ports {adc_d_p[*]}] +set_input_delay -clock [get_clocks adc_dco_p] -min 0.2 [get_ports {adc_d_p[*]}] + +# ============================================================================ +# FT601 USB 3.0 INTERFACE — ACTIVE: NO PHYSICAL CONNECTIONS +# ============================================================================ +# The FT601 chip (U6, FT601Q-B-T) is placed in the Eagle schematic but has +# ZERO net connections — no signals are routed between it and the FPGA. +# Bank 35 (which would logically host FT601 signals) has no signal pins +# connected, only VCCO_35 power. +# +# ALL FT601 constraints are commented out. The RTL module usb_data_interface.v +# instantiates the FT601 interface, but it cannot function without physical +# pin assignments. To use USB, the schematic must be updated to wire the +# FT601 to FPGA Bank 35 pins, and then these constraints can be populated. +# +# Ports affected (from radar_system_top.v): +# ft601_data[31:0], ft601_be[1:0], ft601_txe_n, ft601_rxf_n, ft601_txe, +# ft601_rxf, ft601_wr_n, ft601_rd_n, ft601_oe_n, ft601_siwu_n, +# ft601_srb[1:0], ft601_swb[1:0], ft601_clk_out, ft601_clk_in +# +# TODO: Wire FT601 in schematic, then assign pins here. +# ============================================================================ + +# ============================================================================ +# STATUS / DEBUG OUTPUTS — NO PHYSICAL CONNECTIONS +# ============================================================================ +# The following RTL output ports have no corresponding FPGA pins in the +# schematic. The only FPGA→STM32 outputs available are DIG_5 (H11), +# DIG_6 (G12), and DIG_7 (H12) — only 3 pins for potentially 60+ signals. +# +# These constraints are commented out. If status readback is needed, either: +# (a) Multiplex selected status bits onto DIG_5/6/7, or +# (b) Send status data over the SPI interface, or +# (c) Route through USB once FT601 is wired. +# +# Ports affected: +# current_elevation[5:0], current_azimuth[5:0], current_chirp[5:0], +# new_chirp_frame, dbg_doppler_data[31:0], dbg_doppler_valid, +# dbg_doppler_bin[4:0], dbg_range_bin[5:0], system_status[3:0] +# ============================================================================ + +# ============================================================================ +# TIMING EXCEPTIONS +# ============================================================================ + +# False paths for asynchronous STM32 control signals (active-edge toggle interface) +set_false_path -from [get_ports {stm32_new_*}] +set_false_path -from [get_ports {stm32_mixers_enable}] + +# -------------------------------------------------------------------------- +# Async reset recovery/removal false paths +# +# The async reset (reset_n) is held asserted for multiple clock cycles during +# power-on and system reset. The recovery/removal timing checks on CLR pins +# are over-constrained for this use case: +# - reset_sync_reg[1] fans out to 1000+ registers across the FPGA +# - Route delay alone exceeds the clock period (18+ ns for 10ns period) +# - Reset deassertion order is not functionally critical — all registers +# come out of reset within a few cycles of each other +# -------------------------------------------------------------------------- +set_false_path -from [get_cells reset_sync_reg[*]] -to [get_pins -filter {REF_PIN_NAME == CLR} -of_objects [get_cells -hierarchical -filter {PRIMITIVE_TYPE =~ REGISTER.*.*}]] + +# -------------------------------------------------------------------------- +# Clock Domain Crossing false paths +# -------------------------------------------------------------------------- + +# clk_100m ↔ adc_dco_p (400 MHz): DDC has internal CDC synchronizers +set_false_path -from [get_clocks clk_100m] -to [get_clocks adc_dco_p] +set_false_path -from [get_clocks adc_dco_p] -to [get_clocks clk_100m] + +# clk_100m ↔ clk_120m_dac: CDC via synchronizers in radar_system_top +set_false_path -from [get_clocks clk_100m] -to [get_clocks clk_120m_dac] +set_false_path -from [get_clocks clk_120m_dac] -to [get_clocks clk_100m] + +# FT601 CDC paths removed — no ft601_clk_in clock defined (chip unwired) + +# ============================================================================ +# PHYSICAL CONSTRAINTS +# ============================================================================ + +# Pull up unused pins to prevent floating inputs +set_property BITSTREAM.CONFIG.UNUSEDPIN Pullup [current_design] + +# ============================================================================ +# ADDITIONAL NOTES +# ============================================================================ +# +# 1. ADC Sampling Clock: FPGA_ADC_CLOCK_P/N (N11/N12) is the 400 MHz LVDS +# clock from AD9523 OUT5 that drives the AD9484. It connects to FPGA MRCC +# pins but is not used as an FPGA clock input — the ADC returns data with +# its own DCO (adc_dco_p/n on N14/P14). +# +# 2. Clock Test: FPGA_CLOCK_TEST (H14) is a 20 MHz LVCMOS output from the +# FPGA, configured by AD9523 OUT7. Not currently used in RTL. +# +# 3. SPI Flash: FPGA_FLASH_CS (E8), FPGA_FLASH_CLK (J13), +# FPGA_FLASH_D0 (J14), D1 (K15), D2 (K16), D3 (L12), unnamed (L13). +# These are typically handled by Vivado bitstream configuration and do +# not need explicit XDC constraints for user logic. +# +# 4. JTAG: FPGA_TCK (L7), FPGA_TDI (N7), FPGA_TDO (N8), FPGA_TMS (M7). +# Dedicated pins — no XDC constraints needed. +# +# 5. dac_clk port: The RTL top module declares `dac_clk` as an output, but +# the physical board wires the DAC clock (AD9708 CLOCK pin) directly from +# the AD9523, not from the FPGA. This port should be removed from the RTL +# or left unconnected. It currently just assigns clk_120m_dac passthrough. +# +# ============================================================================ +# END OF CONSTRAINTS +# ============================================================================ diff --git a/9_Firmware/9_2_FPGA/dac_interface_single.v b/9_Firmware/9_2_FPGA/dac_interface_single.v index f912111..ca20841 100644 --- a/9_Firmware/9_2_FPGA/dac_interface_single.v +++ b/9_Firmware/9_2_FPGA/dac_interface_single.v @@ -3,24 +3,79 @@ module dac_interface_enhanced ( input wire reset_n, input wire [7:0] chirp_data, input wire chirp_valid, - output reg [7:0] dac_data, + output wire [7:0] dac_data, output wire dac_clk, - output wire dac_sleep + output wire dac_sleep ); -// Register DAC data to meet timing +// ============================================================================ +// DAC data register (fabric FF — feeds ODDR D1/D2 inputs) +// ============================================================================ +reg [7:0] dac_data_reg; + always @(posedge clk_120m or negedge reset_n) begin if (!reset_n) begin - dac_data <= 8'd128; // Center value + dac_data_reg <= 8'd128; // Center value end else if (chirp_valid) begin - dac_data <= chirp_data; + dac_data_reg <= chirp_data; end else begin - dac_data <= 8'd128; // Default to center when no chirp + dac_data_reg <= 8'd128; // Default to center when no chirp end end -// DAC clock is same as input clock (120MHz) +`ifndef SIMULATION +// ============================================================================ +// ODDR for dac_clk forwarding (Xilinx 7-series) +// D1=1, D2=0 produces a clock replica aligned to clk_120m rising edge. +// The ODDR is placed in the IOB, giving near-zero skew between the +// forwarded clock and ODDR data outputs in the same bank. +// ============================================================================ +ODDR #( + .DDR_CLK_EDGE("OPPOSITE_EDGE"), + .INIT(1'b0), + .SRTYPE("SYNC") +) oddr_dac_clk ( + .Q(dac_clk), + .C(clk_120m), + .CE(1'b1), + .D1(1'b1), + .D2(1'b0), + .R(1'b0), + .S(1'b0) +); + +// ============================================================================ +// ODDR for dac_data[7:0] — packs output FFs into IOBs +// D1=D2=same value → SDR behavior through ODDR, but placed in IOB. +// This eliminates fabric routing delay to the output pad. +// ============================================================================ +genvar i; +generate + for (i = 0; i < 8; i = i + 1) begin : oddr_dac_data_gen + ODDR #( + .DDR_CLK_EDGE("OPPOSITE_EDGE"), + .INIT(1'b0), + .SRTYPE("SYNC") + ) oddr_dac_data ( + .Q(dac_data[i]), + .C(clk_120m), + .CE(1'b1), + .D1(dac_data_reg[i]), + .D2(dac_data_reg[i]), + .R(1'b0), + .S(1'b0) + ); + end +endgenerate + +`else +// ============================================================================ +// Simulation behavioral equivalent +// ============================================================================ assign dac_clk = clk_120m; +assign dac_data = dac_data_reg; +`endif + assign dac_sleep = 1'b0; endmodule \ No newline at end of file diff --git a/9_Firmware/9_2_FPGA/usb_data_interface.v b/9_Firmware/9_2_FPGA/usb_data_interface.v index b1ce460..1382cc0 100644 --- a/9_Firmware/9_2_FPGA/usb_data_interface.v +++ b/9_Firmware/9_2_FPGA/usb_data_interface.v @@ -31,7 +31,7 @@ module usb_data_interface ( input wire [1:0] ft601_swb, // Selected write buffer // Clock - output reg ft601_clk_out, // Output clock to FT601 (optional) + output wire ft601_clk_out, // Output clock to FT601 (forwarded via ODDR) input wire ft601_clk_in // Clock from FT601 (60/100MHz) ); @@ -223,13 +223,39 @@ always @(posedge ft601_clk_in or negedge reset_n) begin end end -// Generate clock for FT601 if needed (optional) -always @(posedge clk or negedge reset_n) begin - if (!reset_n) begin - ft601_clk_out <= 0; - end else begin - ft601_clk_out <= ~ft601_clk_out; // Divide by 2 from main clock - end +// ============================================================================ +// FT601 clock output forwarding +// ============================================================================ +// Forward ft601_clk_in back out via ODDR so that the forwarded clock at the +// pin has the same insertion delay as the data outputs (both go through the +// same BUFG). This makes the output delay analysis relative to the generated +// clock at the pin, where insertion delays cancel. + +`ifndef SIMULATION +ODDR #( + .DDR_CLK_EDGE("OPPOSITE_EDGE"), + .INIT(1'b0), + .SRTYPE("SYNC") +) oddr_ft601_clk ( + .Q(ft601_clk_out), + .C(ft601_clk_in), + .CE(1'b1), + .D1(1'b1), + .D2(1'b0), + .R(1'b0), + .S(1'b0) +); +`else +// Simulation: behavioral clock forwarding +reg ft601_clk_out_sim; +always @(posedge ft601_clk_in or negedge reset_n) begin + if (!reset_n) + ft601_clk_out_sim <= 1'b0; + else + ft601_clk_out_sim <= 1'b1; end +// In simulation, just pass the clock through +assign ft601_clk_out = ft601_clk_in; +`endif endmodule \ No newline at end of file