CycloneIV-E external ADC parallel interface timings
Hi all.
I'm interfacing a CycloneIV-E to a AD9266 ADC and I'm struggling trying to close timings.
FPGA design has one 100MHz pll clock; the adc is clocked with a divide-by-two register (=50MHz); data from adc is 8bit wide, double data rate: it outputs even bits at one 100MHz clock cycle, and odd bits at the next 100MHz clock cycle.
This is the rtl view that generates the 50MHz clock (adc_clk) and latches the data (data[7:0]) to two registers with odd and even data. To avoid muxes (is this a wise choice?) the two latch registers are filled with odd and even bits at the odd and even positions and then or-ed together:
These are the .sdc constraints:
# Clock definition
create_generated_clock -name {ad9266_clk_reg} -source [get_pins {bk39_common_inst|pll_inst|altpll_component|auto_generated|pll1|clk[0]}] -divide_by 2 [get_registers {rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_reg}]
create_generated_clock -name {ad9266_clk} -source [get_registers {rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_reg}] [get_ports {rf_in_adc_clk}]
#delays (from datasheets and pcb design)
set ad9266_dco_tpd_rising_clk_max 4.04
set ad9266_dco_tpd_rising_clk_min 1.86
set ad9266_data_tpd_rising_clk_max 3.9
set ad9266_data_tpd_rising_clk_min 1.84
set ad9266_clk_tpd_delay_max 1.5
set ad9266_clk_tpd_delay_min 0.5
set ad9266_clk_trace_delay_max 0.15
set ad9266_clk_trace_delay_min 0.05
set ad9266_data_trace_delay_max 0.15
set ad9266_data_trace_delay_min 0.05
set ad9266_dco_delay_max [expr $ad9266_data_trace_delay_max + $ad9266_dco_tpd_rising_clk_max - $ad9266_clk_trace_delay_min - $ad9266_clk_tpd_delay_min]
set ad9266_dco_delay_min [expr $ad9266_data_trace_delay_min - $ad9266_dco_tpd_rising_clk_min - $ad9266_clk_trace_delay_max - $ad9266_clk_tpd_delay_max]
set ad9266_data_delay_max [expr $ad9266_data_trace_delay_max + $ad9266_data_tpd_rising_clk_max - $ad9266_clk_trace_delay_min - $ad9266_clk_tpd_delay_min]
set ad9266_data_delay_min [expr $ad9266_data_trace_delay_min - $ad9266_data_tpd_rising_clk_min - $ad9266_clk_trace_delay_max - $ad9266_clk_tpd_delay_max]
#input delay constraints (ddr)
set_input_delay -clock { ad9266_clk } -max $ad9266_dco_delay_max [get_ports {rf_in_adc_dco}]
set_input_delay -clock { ad9266_clk } -min $ad9266_dco_delay_min [get_ports {rf_in_adc_dco}]
set_input_delay -clock { ad9266_clk } -clock_fall -max $ad9266_dco_delay_max [get_ports {rf_in_adc_dco}] -add_delay
set_input_delay -clock { ad9266_clk } -clock_fall -min $ad9266_dco_delay_min [get_ports {rf_in_adc_dco}] -add_delay
set_input_delay -clock { ad9266_clk } -max $ad9266_data_delay_max [get_ports {rf_in_adc_data[*]}]
set_input_delay -clock { ad9266_clk } -min $ad9266_data_delay_min [get_ports {rf_in_adc_data[*]}]
set_input_delay -clock { ad9266_clk } -clock_fall -max $ad9266_data_delay_max [get_ports {rf_in_adc_data[*]}] -add_delay
set_input_delay -clock { ad9266_clk } -clock_fall -min $ad9266_data_delay_min [get_ports {rf_in_adc_data[*]}] -add_delay
Timequest reports all paths failing setup, with ~3.5ns of negative slack:
Tried "Fast input" and "Fast output" assignments:
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_reg"
set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to "rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_reg"
set_instance_assignment -name FAST_INPUT_REGISTER ON -to "rf_in:rf_in_inst|ad9266:adc_inst|dco_adc_data_odd"
set_instance_assignment -name FAST_INPUT_REGISTER ON -to "rf_in:rf_in_inst|ad9266:adc_inst|dco_adc_data_even"
But no big improvement:
I've tried to insert a pipeline for data(in) and clock(out):
Updated .sdc constraints:
create_generated_clock -name {ad9266_clk_reg} -source [get_pins {bk39_common_inst|pll_inst|altpll_component|auto_generated|pll1|clk[0]}] -divide_by 2 [get_registers {rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_pipeline}]
create_generated_clock -name {ad9266_clk} -source [get_registers {rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_pipeline}] [get_ports {rf_in_adc_clk}]
Updated fast i/o assignments:
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to "rf_in:rf_in_inst|ad9266:adc_inst|adc_clk_pipeline"
set_instance_assignment -name FAST_INPUT_REGISTER ON -to "rf_in:rf_in_inst|ad9266:adc_inst|adc_pipeline"
Bit of improvement, but still not a game changer:
Timequest is measuring a beefy delay from I/O pin and the first register:
11.529 3.284 data path
8.245 0.000 FF IC 1 IOIBUF_X0_Y11_N8 rf_in_adc_dco~input|i
9.087 0.842 FF CELL 1 IOIBUF_X0_Y11_N8 rf_in_adc_dco~input|o
11.281 2.194 FF IC 1 FF_X0_Y11_N10 rf_in_inst|adc_inst|adc_pipeline[8]|d
11.529 0.248 FF CELL 1 FF_X0_Y11_N10 rf_in:rf_in_inst|ad9266:adc_inst|adc_pipeline[8]
The contribution of .sdc delay is 3.64ns, about a third of the net delay from IOIBUF_X0_Y11_N8 to FF_X0_Y11_N10.
pipeline register are placed close to I/O, so I quite don't get where this delay is coming from:
pipeline register is then routed to the actual data register, with a "long" path shown in chip planner:
Albeit long in chip planner, the delay is quite short:
report_path -from rf_in:rf_in_inst|ad9266:adc_inst|adc_pipeline[8] -npaths 100 -panel_name {Report Path} -multi_corner
Report Path: Found 16 paths. Longest delay is 2.956
I'm having really a bad times trying to make sense from this data.
Am I missing something? Hints for timings closure?
Thank you!!!