ad9484_interface_400m.v
1 module ad9484_interface_400m ( 2 // ADC Physical Interface (LVDS) 3 input wire [7:0] adc_d_p, // ADC Data P 4 input wire [7:0] adc_d_n, // ADC Data N 5 input wire adc_dco_p, // Data Clock Output P (400MHz) 6 input wire adc_dco_n, // Data Clock Output N (400MHz) 7 8 // System Interface 9 input wire sys_clk, // 100MHz system clock (for control only) 10 input wire reset_n, 11 12 // Output at 400MHz domain 13 output wire [7:0] adc_data_400m, // ADC data at 400MHz 14 output wire adc_data_valid_400m, // Valid at 400MHz 15 output wire adc_dco_bufg // Buffered 400MHz DCO clock for downstream use 16 ); 17 18 // LVDS to single-ended conversion 19 wire [7:0] adc_data; 20 wire adc_dco; 21 22 // IBUFDS for each data bit 23 // NOTE: IOSTANDARD and DIFF_TERM are set via XDC constraints, not RTL 24 // parameters, to support multiple FPGA targets with different bank voltages: 25 // - XC7A200T (FBG484): Bank 14 VCCO = 2.5V → LVDS_25 26 // - XC7A50T (FTG256): Bank 14 VCCO = 3.3V → LVDS_33 27 genvar i; 28 generate 29 for (i = 0; i < 8; i = i + 1) begin : data_buffers 30 IBUFDS #( 31 .DIFF_TERM("FALSE"), // Overridden by XDC DIFF_TERM property 32 .IOSTANDARD("DEFAULT") // Overridden by XDC IOSTANDARD property 33 ) ibufds_data ( 34 .O(adc_data[i]), 35 .I(adc_d_p[i]), 36 .IB(adc_d_n[i]) 37 ); 38 end 39 endgenerate 40 41 // IBUFDS for DCO 42 IBUFDS #( 43 .DIFF_TERM("FALSE"), // Overridden by XDC DIFF_TERM property 44 .IOSTANDARD("DEFAULT") // Overridden by XDC IOSTANDARD property 45 ) ibufds_dco ( 46 .O(adc_dco), 47 .I(adc_dco_p), 48 .IB(adc_dco_n) 49 ); 50 51 // ============================================================================ 52 // Clock buffering strategy for source-synchronous ADC interface: 53 // 54 // BUFIO: Near-zero insertion delay, can only drive IOB primitives (IDDR). 55 // Used for IDDR clocking to match the data path delay through IBUFDS. 56 // This eliminates the hold violation caused by BUFG insertion delay. 57 // 58 // BUFG: Global clock buffer for fabric logic (downstream processing). 59 // Has ~4 ns insertion delay but that's fine for fabric-to-fabric paths. 60 // ============================================================================ 61 wire adc_dco_bufio; // Near-zero delay — drives IDDR only 62 wire adc_dco_buffered; // BUFG output — drives fabric logic 63 64 BUFIO bufio_dco ( 65 .I(adc_dco), 66 .O(adc_dco_bufio) 67 ); 68 69 // MMCME2 jitter-cleaning wrapper replaces the direct BUFG. 70 // The PLL feedback loop attenuates input jitter from ~50 ps to ~20-30 ps, 71 // reducing clock uncertainty and improving WNS on the 400 MHz CIC path. 72 wire mmcm_locked; 73 74 adc_clk_mmcm mmcm_inst ( 75 .clk_in (adc_dco), // 400 MHz from IBUFDS output 76 .reset_n (reset_n), 77 .clk_400m_out (adc_dco_buffered), // Jitter-cleaned 400 MHz on BUFG 78 .mmcm_locked (mmcm_locked) 79 ); 80 assign adc_dco_bufg = adc_dco_buffered; 81 82 // IDDR for capturing DDR data 83 wire [7:0] adc_data_rise; // Data on rising edge (BUFIO domain) 84 wire [7:0] adc_data_fall; // Data on falling edge (BUFIO domain) 85 86 genvar j; 87 generate 88 for (j = 0; j < 8; j = j + 1) begin : iddr_gen 89 IDDR #( 90 .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), 91 .INIT_Q1(1'b0), 92 .INIT_Q2(1'b0), 93 .SRTYPE("SYNC") 94 ) iddr_inst ( 95 .Q1(adc_data_rise[j]), // Rising edge data 96 .Q2(adc_data_fall[j]), // Falling edge data 97 .C(adc_dco_bufio), // BUFIO clock (near-zero insertion delay) 98 .CE(1'b1), 99 .D(adc_data[j]), 100 .R(1'b0), 101 .S(1'b0) 102 ); 103 end 104 endgenerate 105 106 // ============================================================================ 107 // Re-register IDDR outputs into BUFG domain 108 // IDDR with SAME_EDGE_PIPELINED produces outputs stable for a full clock cycle. 109 // BUFIO and BUFG are derived from the same source (adc_dco), so they are 110 // frequency-matched. This single register stage transfers from IOB (BUFIO) 111 // to fabric (BUFG) with guaranteed timing. 112 // ============================================================================ 113 reg [7:0] adc_data_rise_bufg; 114 reg [7:0] adc_data_fall_bufg; 115 116 always @(posedge adc_dco_buffered) begin 117 adc_data_rise_bufg <= adc_data_rise; 118 adc_data_fall_bufg <= adc_data_fall; 119 end 120 121 // Combine rising and falling edge data to get 400MSPS stream 122 reg [7:0] adc_data_400m_reg; 123 reg adc_data_valid_400m_reg; 124 reg dco_phase; 125 126 // ── Reset synchronizer ──────────────────────────────────────── 127 // reset_n comes from the 100 MHz sys_clk domain. Assertion (going low) 128 // is asynchronous and safe — the FFs enter reset instantly. De-assertion 129 // (going high) must be synchronised to adc_dco_buffered to avoid 130 // metastability. This is the classic "async assert, sync de-assert" pattern. 131 // 132 // mmcm_locked gates de-assertion: the 400 MHz domain stays in reset until 133 // the MMCM PLL has locked and the jitter-cleaned clock is stable. 134 (* ASYNC_REG = "TRUE" *) reg [1:0] reset_sync_400m; 135 wire reset_n_400m; 136 wire reset_n_gated = reset_n & mmcm_locked; 137 138 always @(posedge adc_dco_buffered or negedge reset_n_gated) begin 139 if (!reset_n_gated) 140 reset_sync_400m <= 2'b00; // async assert (or MMCM not locked) 141 else 142 reset_sync_400m <= {reset_sync_400m[0], 1'b1}; // sync de-assert 143 end 144 assign reset_n_400m = reset_sync_400m[1]; 145 146 always @(posedge adc_dco_buffered or negedge reset_n_400m) begin 147 if (!reset_n_400m) begin 148 adc_data_400m_reg <= 8'b0; 149 adc_data_valid_400m_reg <= 1'b0; 150 dco_phase <= 1'b0; 151 end else begin 152 dco_phase <= ~dco_phase; 153 154 if (dco_phase) begin 155 // Output falling edge data (completes the 400MSPS stream) 156 adc_data_400m_reg <= adc_data_fall_bufg; 157 end else begin 158 // Output rising edge data 159 adc_data_400m_reg <= adc_data_rise_bufg; 160 end 161 162 adc_data_valid_400m_reg <= 1'b1; // Always valid when ADC is running 163 end 164 end 165 166 assign adc_data_400m = adc_data_400m_reg; 167 assign adc_data_valid_400m = adc_data_valid_400m_reg; 168 169 endmodule