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)
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user