From 07ae2ba989d4465fbc7b1a97b29ecac6fc48744a Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 24 Aug 2025 11:26:14 -0700 Subject: [PATCH] eth: Add RFDC to ZCU111 example design Signed-off-by: Alex Forencich --- src/eth/example/ZCU111/fpga/README.md | 2 +- src/eth/example/ZCU111/fpga/fpga.xdc | 76 +- src/eth/example/ZCU111/fpga/fpga/Makefile | 3 + src/eth/example/ZCU111/fpga/fpga_10g/Makefile | 3 + .../ZCU111/fpga/ip/usp_rfdc_1ghz_1gsps.tcl | 143 +++ .../example/ZCU111/fpga/pll/LMK04208_250.txt | 88 ++ .../ZCU111/fpga/pll/LMX2594_250_1000.txt | 114 ++ .../example/ZCU111/fpga/pll/pll_i2c_init.py | 684 +++++++++++ .../example/ZCU111/fpga/pll/pll_i2c_init.sv | 1083 +++++++++++++++++ src/eth/example/ZCU111/fpga/rtl/fpga.sv | 734 ++++++++++- src/eth/example/ZCU111/fpga/rtl/fpga_core.sv | 159 ++- .../example/ZCU111/fpga/tb/fpga_core/Makefile | 4 +- .../fpga/tb/fpga_core/test_fpga_core.py | 6 +- .../fpga/tb/fpga_core/test_fpga_core.sv | 186 +++ 14 files changed, 3263 insertions(+), 22 deletions(-) create mode 100644 src/eth/example/ZCU111/fpga/ip/usp_rfdc_1ghz_1gsps.tcl create mode 100644 src/eth/example/ZCU111/fpga/pll/LMK04208_250.txt create mode 100644 src/eth/example/ZCU111/fpga/pll/LMX2594_250_1000.txt create mode 100755 src/eth/example/ZCU111/fpga/pll/pll_i2c_init.py create mode 100644 src/eth/example/ZCU111/fpga/pll/pll_i2c_init.sv create mode 100644 src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.sv diff --git a/src/eth/example/ZCU111/fpga/README.md b/src/eth/example/ZCU111/fpga/README.md index 4e0475f..3cc5c7f 100644 --- a/src/eth/example/ZCU111/fpga/README.md +++ b/src/eth/example/ZCU111/fpga/README.md @@ -4,7 +4,7 @@ This example design targets the Xilinx ZCU111 FPGA board. -The design places looped-back MACs on the SFP+ ports, as well as XFCP on the USB UART for monitoring and control. +The design places looped-back MACs on the SFP+ ports, as well as XFCP on the USB UART for monitoring and control. The RF data converters are also enabled at 1 Gsps per channel. * USB UART * XFCP (3 Mbaud) diff --git a/src/eth/example/ZCU111/fpga/fpga.xdc b/src/eth/example/ZCU111/fpga/fpga.xdc index 197024e..81c0871 100644 --- a/src/eth/example/ZCU111/fpga/fpga.xdc +++ b/src/eth/example/ZCU111/fpga/fpga.xdc @@ -37,7 +37,7 @@ set_false_path -to [get_ports {led[*]}] set_output_delay 0 [get_ports {led[*]}] # Reset button -set_property -dict {LOC AF15 IOSTANDARD LVCMOS18} [get_ports reset] ;# SW15 +set_property -dict {LOC AF15 IOSTANDARD LVCMOS18} [get_ports reset] ;# SW20 set_false_path -from [get_ports {reset}] set_input_delay 0 [get_ports {reset}] @@ -102,17 +102,21 @@ set_output_delay 0 [get_ports {uart_txd uart_cts}] set_false_path -from [get_ports {uart_rxd uart_rts}] set_input_delay 0 [get_ports {uart_rxd uart_rts}] - # I2C interfaces -#set_property -dict {LOC AT16 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports i2c0_scl] -#set_property -dict {LOC AW16 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports i2c0_sda] -#set_property -dict {LOC AH19 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports i2c1_scl] -#set_property -dict {LOC AL21 IOSTANDARD LVCMOS33 SLEW SLOW DRIVE 8} [get_ports i2c1_sda] +set_property -dict {LOC AT16 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports i2c0_scl] +set_property -dict {LOC AW16 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports i2c0_sda] +set_property -dict {LOC AV16 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports i2c1_scl] +set_property -dict {LOC AV13 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 12 PULLUP true} [get_ports i2c1_sda] -#set_false_path -to [get_ports {i2c1_sda i2c1_scl}] -#set_output_delay 0 [get_ports {i2c1_sda i2c1_scl}] -#set_false_path -from [get_ports {i2c1_sda i2c1_scl}] -#set_input_delay 0 [get_ports {i2c1_sda i2c1_scl}] +set_false_path -to [get_ports {i2c0_sda i2c0_scl}] +set_output_delay 0 [get_ports {i2c0_sda i2c0_scl}] +set_false_path -from [get_ports {i2c0_sda i2c0_scl}] +set_input_delay 0 [get_ports {i2c0_sda i2c0_scl}] + +set_false_path -to [get_ports {i2c1_sda i2c1_scl}] +set_output_delay 0 [get_ports {i2c1_sda i2c1_scl}] +set_false_path -from [get_ports {i2c1_sda i2c1_scl}] +set_input_delay 0 [get_ports {i2c1_sda i2c1_scl}] # SFP28 Interface set_property -dict {LOC AA38} [get_ports {sfp_rx_p[0]}] ;# MGTYRXP0_128 GTYE4_CHANNEL_X1Y12 / GTYE4_COMMON_X1Y3 @@ -147,3 +151,55 @@ create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports {sfp_mgt_refclk_0_p set_false_path -to [get_ports {sfp_tx_disable_b[*]}] set_output_delay 0 [get_ports {sfp_tx_disable_b[*]}] + +# RFDC +set_property -dict {LOC AP2 } [get_ports {adc_vin_p[0]}] ;# ADC_VIN_I01_224_P from J47.G9 +set_property -dict {LOC AP1 } [get_ports {adc_vin_n[0]}] ;# ADC_VIN_I01_224_N from J47.F9 +set_property -dict {LOC AM2 } [get_ports {adc_vin_p[1]}] ;# ADC_VIN_I23_224_P from J47.C10 +set_property -dict {LOC AM1 } [get_ports {adc_vin_n[1]}] ;# ADC_VIN_I23_224_N from J47.B10 +set_property -dict {LOC AK2 } [get_ports {adc_vin_p[2]}] ;# ADC_VIN_I01_225_P from J47.G12 +set_property -dict {LOC AK1 } [get_ports {adc_vin_n[2]}] ;# ADC_VIN_I01_225_N from J47.F12 +set_property -dict {LOC AH2 } [get_ports {adc_vin_p[3]}] ;# ADC_VIN_I23_225_P from J47.C13 +set_property -dict {LOC AH1 } [get_ports {adc_vin_n[3]}] ;# ADC_VIN_I23_225_N from J47.B13 +set_property -dict {LOC AF2 } [get_ports {adc_vin_p[4]}] ;# ADC_VIN_I01_226_P from J47.G15 +set_property -dict {LOC AF1 } [get_ports {adc_vin_n[4]}] ;# ADC_VIN_I01_226_N from J47.F15 +set_property -dict {LOC AD2 } [get_ports {adc_vin_p[5]}] ;# ADC_VIN_I23_226_P from J47.C16 +set_property -dict {LOC AD1 } [get_ports {adc_vin_n[5]}] ;# ADC_VIN_I23_226_N from J47.B16 +set_property -dict {LOC AB2 } [get_ports {adc_vin_p[6]}] ;# ADC_VIN_I01_227_P from J47.G18 +set_property -dict {LOC AB1 } [get_ports {adc_vin_n[6]}] ;# ADC_VIN_I01_227_N from J47.F18 +set_property -dict {LOC Y2 } [get_ports {adc_vin_p[7]}] ;# ADC_VIN_I23_227_P from J47.C19 +set_property -dict {LOC Y1 } [get_ports {adc_vin_n[7]}] ;# ADC_VIN_I23_227_N from J47.B19 + +set_property -dict {LOC AF5 } [get_ports {adc_refclk_0_p}] ;# ADC_224_REFCLK_P from U102.23 RFoutAP +set_property -dict {LOC AF4 } [get_ports {adc_refclk_0_n}] ;# ADC_224_REFCLK_N from U102.22 RFoutAN +set_property -dict {LOC AD5 } [get_ports {adc_refclk_1_p}] ;# ADC_225_REFCLK_P from U102.19 RFoutBP +set_property -dict {LOC AD4 } [get_ports {adc_refclk_1_n}] ;# ADC_225_REFCLK_N from U102.18 RFoutBN +set_property -dict {LOC AB5 } [get_ports {adc_refclk_2_p}] ;# ADC_226_REFCLK_P from U103.23 RFoutAP +set_property -dict {LOC AB4 } [get_ports {adc_refclk_2_n}] ;# ADC_226_REFCLK_N from U103.22 RFoutAN +set_property -dict {LOC Y5 } [get_ports {adc_refclk_3_p}] ;# ADC_227_REFCLK_P from U103.19 RFoutBP +set_property -dict {LOC Y4 } [get_ports {adc_refclk_3_n}] ;# ADC_227_REFCLK_N from U103.18 RFoutBN + +set_property -dict {LOC U2 } [get_ports {dac_vout_p[0]}] ;# DAC_VOUT0_228_P from J94.G9 +set_property -dict {LOC U1 } [get_ports {dac_vout_n[0]}] ;# DAC_VOUT0_228_N from J94.F9 +set_property -dict {LOC R2 } [get_ports {dac_vout_p[1]}] ;# DAC_VOUT1_228_P from J94.C10 +set_property -dict {LOC R1 } [get_ports {dac_vout_n[1]}] ;# DAC_VOUT1_228_N from J94.B10 +set_property -dict {LOC N2 } [get_ports {dac_vout_p[2]}] ;# DAC_VOUT2_228_P from J94.G12 +set_property -dict {LOC N1 } [get_ports {dac_vout_n[2]}] ;# DAC_VOUT2_228_N from J94.F12 +set_property -dict {LOC L2 } [get_ports {dac_vout_p[3]}] ;# DAC_VOUT3_228_P from J94.C13 +set_property -dict {LOC L1 } [get_ports {dac_vout_n[3]}] ;# DAC_VOUT3_228_N from J94.B13 +set_property -dict {LOC J2 } [get_ports {dac_vout_p[4]}] ;# DAC_VOUT0_229_P from J94.G15 +set_property -dict {LOC J1 } [get_ports {dac_vout_n[4]}] ;# DAC_VOUT0_229_N from J94.F15 +set_property -dict {LOC G2 } [get_ports {dac_vout_p[5]}] ;# DAC_VOUT1_229_P from J94.C16 +set_property -dict {LOC G1 } [get_ports {dac_vout_n[5]}] ;# DAC_VOUT1_229_N from J94.B16 +set_property -dict {LOC E2 } [get_ports {dac_vout_p[6]}] ;# DAC_VOUT2_229_P from J94.G18 +set_property -dict {LOC E1 } [get_ports {dac_vout_n[6]}] ;# DAC_VOUT2_229_N from J94.F18 +set_property -dict {LOC C2 } [get_ports {dac_vout_p[7]}] ;# DAC_VOUT3_229_P from J94.C19 +set_property -dict {LOC C1 } [get_ports {dac_vout_n[7]}] ;# DAC_VOUT3_229_N from J94.B19 + +set_property -dict {LOC R5 } [get_ports {dac_refclk_0_p}] ;# DAC_228_REFCLK_P from U104.23 RFoutAP +set_property -dict {LOC R4 } [get_ports {dac_refclk_0_n}] ;# DAC_228_REFCLK_N from U104.22 RFoutAN +set_property -dict {LOC N5 } [get_ports {dac_refclk_1_p}] ;# DAC_229_REFCLK_P from U104.19 RFoutBP +set_property -dict {LOC N4 } [get_ports {dac_refclk_1_n}] ;# DAC_229_REFCLK_N from U104.18 RFoutBN + +set_property -dict {LOC U5 } [get_ports {rfdc_sysref_p}] ;# SYSREF_P_228 from U90.13 CLKout1_P +set_property -dict {LOC U4 } [get_ports {rfdc_sysref_n}] ;# SYSREF_N_228 from U90.14 CLKout1_N diff --git a/src/eth/example/ZCU111/fpga/fpga/Makefile b/src/eth/example/ZCU111/fpga/fpga/Makefile index 408a583..78296f1 100644 --- a/src/eth/example/ZCU111/fpga/fpga/Makefile +++ b/src/eth/example/ZCU111/fpga/fpga/Makefile @@ -18,10 +18,12 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src # Files for synthesis SYN_FILES = $(RTL_DIR)/fpga.sv SYN_FILES += $(RTL_DIR)/fpga_core.sv +SYN_FILES += $(RTL_DIR)/../pll/pll_i2c_init.sv SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f +SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv @@ -36,6 +38,7 @@ XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl # IP IP_TCL_FILES = $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_25g_156.tcl +IP_TCL_FILES += ../ip/usp_rfdc_1ghz_1gsps.tcl # Configuration #CONFIG_TCL_FILES = ./config.tcl diff --git a/src/eth/example/ZCU111/fpga/fpga_10g/Makefile b/src/eth/example/ZCU111/fpga/fpga_10g/Makefile index 7091d67..c2a5d58 100644 --- a/src/eth/example/ZCU111/fpga/fpga_10g/Makefile +++ b/src/eth/example/ZCU111/fpga/fpga_10g/Makefile @@ -18,10 +18,12 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src # Files for synthesis SYN_FILES = $(RTL_DIR)/fpga.sv SYN_FILES += $(RTL_DIR)/fpga_core.sv +SYN_FILES += $(RTL_DIR)/../pll/pll_i2c_init.sv SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f +SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f SYN_FILES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv @@ -36,6 +38,7 @@ XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl # IP IP_TCL_FILES = $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_25g_us_gty_10g_156.tcl +IP_TCL_FILES += ../ip/usp_rfdc_1ghz_1gsps.tcl # Configuration #CONFIG_TCL_FILES = ./config.tcl diff --git a/src/eth/example/ZCU111/fpga/ip/usp_rfdc_1ghz_1gsps.tcl b/src/eth/example/ZCU111/fpga/ip/usp_rfdc_1ghz_1gsps.tcl new file mode 100644 index 0000000..6cbd993 --- /dev/null +++ b/src/eth/example/ZCU111/fpga/ip/usp_rfdc_1ghz_1gsps.tcl @@ -0,0 +1,143 @@ + +create_ip -name usp_rf_data_converter -vendor xilinx.com -library ip -module_name usp_rfdc_0 + +set ADC_RATE {1.0} +set ADC_REFCLK_FREQ {1000.000} +set ADC_OUTCLK_FREQ {62.500} +set ADC_FABRIC_FREQ {250.000} +set ADC_DATA_WIDTH {4} + +set DAC_RATE $ADC_RATE +set DAC_REFCLK_FREQ $ADC_REFCLK_FREQ +set DAC_OUTCLK_FREQ $ADC_OUTCLK_FREQ +set DAC_FABRIC_FREQ $ADC_FABRIC_FREQ +set DAC_DATA_WIDTH $ADC_DATA_WIDTH + +set_property -dict [list \ + CONFIG.Axiclk_Freq {125} \ + CONFIG.DAC_Output_Current {1} \ + CONFIG.DAC_RTS {false} \ + CONFIG.ADC0_Sampling_Rate $ADC_RATE \ + CONFIG.ADC0_Refclk_Freq $ADC_REFCLK_FREQ \ + CONFIG.ADC0_Outclk_Freq $ADC_OUTCLK_FREQ \ + CONFIG.ADC0_Fabric_Freq $ADC_FABRIC_FREQ \ + CONFIG.ADC_Data_Width00 $ADC_DATA_WIDTH \ + CONFIG.ADC_Data_Width01 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice02_Enable {true} \ + CONFIG.ADC_Decimation_Mode02 {1} \ + CONFIG.ADC_Mixer_Type02 {0} \ + CONFIG.ADC_Data_Width02 $ADC_DATA_WIDTH \ + CONFIG.ADC_OBS02 {0} \ + CONFIG.ADC_Slice03_Enable {true} \ + CONFIG.ADC_Decimation_Mode03 {1} \ + CONFIG.ADC_Mixer_Type03 {0} \ + CONFIG.ADC_Data_Width03 $ADC_DATA_WIDTH \ + CONFIG.ADC1_Enable {1} \ + CONFIG.ADC1_Sampling_Rate $ADC_RATE \ + CONFIG.ADC1_Refclk_Freq $ADC_REFCLK_FREQ \ + CONFIG.ADC1_Outclk_Freq $ADC_OUTCLK_FREQ \ + CONFIG.ADC1_Fabric_Freq $ADC_FABRIC_FREQ \ + CONFIG.ADC_Slice10_Enable {true} \ + CONFIG.ADC_Decimation_Mode10 {1} \ + CONFIG.ADC_Mixer_Type10 {0} \ + CONFIG.ADC_Data_Width10 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice11_Enable {true} \ + CONFIG.ADC_Decimation_Mode11 {1} \ + CONFIG.ADC_Mixer_Type11 {0} \ + CONFIG.ADC_Data_Width11 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice12_Enable {true} \ + CONFIG.ADC_Decimation_Mode12 {1} \ + CONFIG.ADC_Mixer_Type12 {0} \ + CONFIG.ADC_Data_Width12 $ADC_DATA_WIDTH \ + CONFIG.ADC_OBS12 {0} \ + CONFIG.ADC_Slice13_Enable {true} \ + CONFIG.ADC_Decimation_Mode13 {1} \ + CONFIG.ADC_Mixer_Type13 {0} \ + CONFIG.ADC_Data_Width13 $ADC_DATA_WIDTH \ + CONFIG.ADC2_Enable {1} \ + CONFIG.ADC2_Sampling_Rate $ADC_RATE \ + CONFIG.ADC2_Refclk_Freq $ADC_REFCLK_FREQ \ + CONFIG.ADC2_Outclk_Freq $ADC_OUTCLK_FREQ \ + CONFIG.ADC2_Fabric_Freq $ADC_FABRIC_FREQ \ + CONFIG.ADC_Slice20_Enable {true} \ + CONFIG.ADC_Decimation_Mode20 {1} \ + CONFIG.ADC_Mixer_Type20 {0} \ + CONFIG.ADC_Data_Width20 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice21_Enable {true} \ + CONFIG.ADC_Decimation_Mode21 {1} \ + CONFIG.ADC_Mixer_Type21 {0} \ + CONFIG.ADC_Data_Width21 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice22_Enable {true} \ + CONFIG.ADC_Decimation_Mode22 {1} \ + CONFIG.ADC_Mixer_Type22 {0} \ + CONFIG.ADC_Data_Width22 $ADC_DATA_WIDTH \ + CONFIG.ADC_OBS22 {0} \ + CONFIG.ADC_Slice23_Enable {true} \ + CONFIG.ADC_Decimation_Mode23 {1} \ + CONFIG.ADC_Mixer_Type23 {0} \ + CONFIG.ADC_Data_Width23 $ADC_DATA_WIDTH \ + CONFIG.ADC3_Enable {1} \ + CONFIG.ADC3_Sampling_Rate $ADC_RATE \ + CONFIG.ADC3_Refclk_Freq $ADC_REFCLK_FREQ \ + CONFIG.ADC3_Outclk_Freq $ADC_OUTCLK_FREQ \ + CONFIG.ADC3_Fabric_Freq $ADC_FABRIC_FREQ \ + CONFIG.ADC_Slice30_Enable {true} \ + CONFIG.ADC_Decimation_Mode30 {1} \ + CONFIG.ADC_Mixer_Type30 {0} \ + CONFIG.ADC_Data_Width30 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice31_Enable {true} \ + CONFIG.ADC_Decimation_Mode31 {1} \ + CONFIG.ADC_Mixer_Type31 {0} \ + CONFIG.ADC_Data_Width31 $ADC_DATA_WIDTH \ + CONFIG.ADC_Slice32_Enable {true} \ + CONFIG.ADC_Decimation_Mode32 {1} \ + CONFIG.ADC_Mixer_Type32 {0} \ + CONFIG.ADC_Data_Width32 $ADC_DATA_WIDTH \ + CONFIG.ADC_OBS32 {0} \ + CONFIG.ADC_Slice33_Enable {true} \ + CONFIG.ADC_Decimation_Mode33 {1} \ + CONFIG.ADC_Mixer_Type33 {0} \ + CONFIG.ADC_Data_Width33 $ADC_DATA_WIDTH \ + CONFIG.DAC0_Enable {1} \ + CONFIG.DAC0_Sampling_Rate $DAC_RATE \ + CONFIG.DAC0_Refclk_Freq $DAC_REFCLK_FREQ \ + CONFIG.DAC0_Outclk_Freq $DAC_OUTCLK_FREQ \ + CONFIG.DAC0_Fabric_Freq $DAC_FABRIC_FREQ \ + CONFIG.DAC_Slice00_Enable {true} \ + CONFIG.DAC_Data_Width00 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode00 {1} \ + CONFIG.DAC_Mixer_Type00 {0} \ + CONFIG.DAC_Slice01_Enable {true} \ + CONFIG.DAC_Data_Width01 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode01 {1} \ + CONFIG.DAC_Mixer_Type01 {0} \ + CONFIG.DAC_Slice02_Enable {true} \ + CONFIG.DAC_Data_Width02 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode02 {1} \ + CONFIG.DAC_Mixer_Type02 {0} \ + CONFIG.DAC_Slice03_Enable {true} \ + CONFIG.DAC_Data_Width03 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode03 {1} \ + CONFIG.DAC_Mixer_Type03 {0} \ + CONFIG.DAC1_Enable {1} \ + CONFIG.DAC1_Sampling_Rate $DAC_RATE \ + CONFIG.DAC1_Refclk_Freq $DAC_REFCLK_FREQ \ + CONFIG.DAC1_Outclk_Freq $DAC_OUTCLK_FREQ \ + CONFIG.DAC1_Fabric_Freq $DAC_FABRIC_FREQ \ + CONFIG.DAC_Slice10_Enable {true} \ + CONFIG.DAC_Data_Width10 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode10 {1} \ + CONFIG.DAC_Mixer_Type10 {0} \ + CONFIG.DAC_Slice11_Enable {true} \ + CONFIG.DAC_Data_Width11 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode11 {1} \ + CONFIG.DAC_Mixer_Type11 {0} \ + CONFIG.DAC_Slice12_Enable {true} \ + CONFIG.DAC_Data_Width12 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode12 {1} \ + CONFIG.DAC_Mixer_Type12 {0} \ + CONFIG.DAC_Slice13_Enable {true} \ + CONFIG.DAC_Data_Width13 $DAC_DATA_WIDTH \ + CONFIG.DAC_Interpolation_Mode13 {1} \ + CONFIG.DAC_Mixer_Type13 {0} \ +] [get_ips usp_rfdc_0] diff --git a/src/eth/example/ZCU111/fpga/pll/LMK04208_250.txt b/src/eth/example/ZCU111/fpga/pll/LMK04208_250.txt new file mode 100644 index 0000000..0ef94d7 --- /dev/null +++ b/src/eth/example/ZCU111/fpga/pll/LMK04208_250.txt @@ -0,0 +1,88 @@ +# Configuration for LMK04208 PLL + +# PLL1 +# CLKin0 = 12.8 MHz TCXO +# CLKin1 = 10 MHz +# CLKin0 R = 800 +# CLKin1 R = 625 +# PFD = in0 / R0 = in1 / R1 = 16 kHz +# N1 = 7680 +# VCO = PFD * N1 = 122.88 MHz +# Ext VCO is 122.88 MHz + +# PLL2 +# 122.88 MHz from ext VCO +# VCO range 2750 - 3072 MHz +# R2 = 384 +# VCODIV = 3 +# N2 P = 5 +# N2 = 625 +# PFD = 122.88 / R2 = 0.32 +# VCO = PFD * VCODIV * P * N2 = 3000 +# VCO/3/4 = 250 MHz +# VCO/3/100 = 10 MHz +# VCO/3/512 = 1.953125 MHz + +# CLKout0: FPGA SYSREF +# CLKout1: DAC 228 SYSREF +# CLKout2: FPGA REFCLK +# CLKout3: SYNC_2594 +# CLKout4: REFCLK_2594 +# CLKout5: SMA + +Data + +# Reset +0x00020000 +0x00000000 + +# CLKout0 DDLY 10, DIV 512 +0x00284000 +# CLKout1 DDLY 10, DIV 512 +0x00284001 +# CLKout2 DDLY 10, DIV 4 +0x00280082 +# CLKout3 DDLY 10, DIV 512 +0x00284003 +# CLKout4 DDLY 10, DIV 4 +0x00280084 +# CLKout5 DDLY 10, DIV 100 +0x00280c85 +# CLKout0 LVDS, CLKout1 LVDS +0x01100006 +# CLKout2 LVDS, CLKout3 LVDS +0x01100007 +# CLKout4 LVDS, CLKout5 LVCMOS +0x06010008 +# RSVD +0x55555549 +# OSCout off, VCO div 3 +0x1000530a +# MODE 0, sync on, SYNC_TYPE input with pull-up, no xtal +0x0400200b +# LD_MUX PLL1&PLL2, SYNC_PLL2_DLD on, EN_TRACK on, holdover disable +0x1b8c016c +# HOLDOVER_MUX readback, DISABLE_DLD1_DET on, CLKin_SELECT_MODE CLKin0, EN_CLKin0 +0x3b00802d +# LOS_TIMEOUT 1200 ns, CLKinX_BUF_TYPE Bipolar, DAC_HIGH_TRIP 63, DAC_LOW_TRIP 0 +0x000fc00e +# MAN_DAC 0, EN_MAN_DAC auto +0x0000000f +# XTAL_LVL 1.65 Vpp +0x01550410 +# PLL2_C4_LF 10pF, PLL2_C3_LF 10 pF, PLL2_R4_LF 200 ohm, PLL2_R3_LF 200 ohm, PLL1_N_DLY 0 ps, PLL1_R_DLY 0 ps, PLL1_WND_SIZE 5.5 ns +0x00000018 +# DAC_CLK_DIV 1023, PLL1_DLD_CNT 16383 +0xffcfffd9 +# PLL2_WND_SIZE 2, EN_PLL2_REF_2X off, PLL2_CP_POL neg, PLL2_CP_GAIN 100, PLL2_DLD_CNT 16383, PLL2_CP_TRI off +0x83afffda +# PLL1_CP_POL pos, PLL1_CP_GAIN 100, CLKinX_PreR_DIV 1, PLL1_R 800, PLL1_CP_TRI off +0x1000c81b +# PLL2_R 384, PLL1_N 7680 +0x1807801c +# OSCin_FREQ 63-127, PLL2_FAST_PDF under 100, PLL2_N_CAL 625 +0x01004e3d +# PLL2_P 5, PLL2_N 625 +0x05004e3e +# READBACK_LE 0 +0x0000001f diff --git a/src/eth/example/ZCU111/fpga/pll/LMX2594_250_1000.txt b/src/eth/example/ZCU111/fpga/pll/LMX2594_250_1000.txt new file mode 100644 index 0000000..cedbce3 --- /dev/null +++ b/src/eth/example/ZCU111/fpga/pll/LMX2594_250_1000.txt @@ -0,0 +1,114 @@ +# Configuration for LMX2594 PLL + +# OSCin = 250 MHz +# VCO range 7.5 - 15 GHz +# R_PRE = 1 +# R = 1 +# PFD = OSCin / (R_PRE * R) = 250 MHz +# N = 32 +# VCO = PFD * N = 8 GHz +# VCO / 8 = 1 GHz + +# Reset +0,0x2412 +0,0x2410 + +# QUICK_RECAL_EN: 0 +# VCO_CAPCTRL_STRT: 0 +78,0x0001 +# CHDIV: 3 (8) +75,0x08c0 +# MASH_RST_COUNT: 50000 (0xc350) +70,0xc350 +# MASH_RST_COUNT: 50000 (0xc350) +69,0x0000 +# LD_DELAY: 1000 (0x3e8) +60,0x03e8 +# LD_TYPE: 1 +59,0x0001 +# INPIN_IGNORE: 1 +# INPIN_HYST: 0 +# INPIN_LVL: 0 +# INPIN_FMT: 0 +58,0x8001 +# OUTB_MUX: 0 (ch div) +46,0x07fc +# OUTA_MUX: 0 (ch div) +# OUT_ISET: 0 (max) +# OUTB_PWR: 31 (0x1f) +45,0xc0df +# OUTA_PWR: 31 (0x1f) +# OUTB_PD: 0 +# OUTA_PD: 0 +# MASH_RESET_N: 0 +# MASH_ORDER: 0 +44,0x1f00 +# PLL_NUM: 0 +43,0x0000 +# PLL_NUM: 0 +42,0x0000 +# MASH_SEED: 0 +41,0x0000 +# MASH_SEED: 0 +40,0x0000 +# PLL_DEN: '1 +39,0xffff +# PLL_DEN: '1 +38,0xffff +# MASH_SEED_EN: 0 +# PFD_DLY_SEL: 2 +37,0x0204 +# PLL_N: 32 (0x20) +36,0x0020 +# PLL_N: 32 (0x20) +34,0x0000 +# CHDIV_DIV2: 1 +31,0x43ec +# VCO_SEL: 7 (VCO7) +# VCO_SEL_FORCE: 0 +20,0xf848 +# VCO_CAPCTRL: 183 (0xb7) +19,0x27b7 +# 18,0x0000 +# VCO_DACISET_STRT: 250 (0xfa) +17,0x00fa +# VCO_DACISET: 128 (0x80) +16,0x0080 +# 15,0x0000 +# CPG: 7 +14,0x1e70 +# PLL_R_PRE: 1 +12,0x5001 +# PLL_R: 1 +11,0x0018 +# MULT: 1 (bypass) +10,0x10d8 +# OSC_2X: 0 +9,0x0604 +# VCO_DACISET_FORCE: 0 +# VCO_CAPCTRL_FORCE: 0 +8,0x2000 +# OUT_FORCE: 0 +7,0x00b2 +# ACAL_CMP_DLY: 10 +4,0x0a43 +# CAL_CLK_DIV: 3 (div 8) +1,0x080b + +# FCAL_HPFD_ADJ: 3 (PFD > 200 MHz) +# FCAL_LPFD_ADJ: 0 (PFD > 10 MHz) +# FCAL_EN: 0 +# MUXOUT_LD_SEL: 0 (readback) +# RESET: 0 +# POWERDOWN: 0 +0,0x2590 + +# Delay 10 msec + +# FCAL_HPFD_ADJ: 3 (PFD > 200 MHz) +# FCAL_LPFD_ADJ: 0 (PFD > 10 MHz) +# FCAL_EN: 1 +# MUXOUT_LD_SEL: 1 (LD) +# RESET: 0 +# POWERDOWN: 0 +0,0x259C diff --git a/src/eth/example/ZCU111/fpga/pll/pll_i2c_init.py b/src/eth/example/ZCU111/fpga/pll/pll_i2c_init.py new file mode 100755 index 0000000..d59bb42 --- /dev/null +++ b/src/eth/example/ZCU111/fpga/pll/pll_i2c_init.py @@ -0,0 +1,684 @@ +#!/usr/bin/env python +""" +Generates an I2C init module for multiple chips +""" + +from jinja2 import Template + + +def lmk04208_cmds(regs, dev_addr=0x2a, mask=0x01): + cmds = [] + + print(f"Reading register list file '{regs}'...") + + with open(regs, "r") as f: + for line in f: + line = line.strip() + if not line or line == "Data": + continue + if line[0] == '#': + cmds.append(f"// {line[1:].strip()}") + + if line.startswith("# Delay"): + cmds.append("cmd_delay(10); // delay 300 ms") + + continue + + data = int(line, 0) + b = data.to_bytes(4, 'big') + + cmds.append(f"cmd_start(7'h{dev_addr:02x});") + cmds.append(f"cmd_wr(8'h{mask:02x}); // SPI transfer, CS mask {mask:#03x}") + cmds.append(f"cmd_wr(8'h{b[0]:02x}); // write {data:#010x}") + cmds.append(f"cmd_wr(8'h{b[1]:02x});") + cmds.append(f"cmd_wr(8'h{b[2]:02x});") + cmds.append(f"cmd_wr(8'h{b[3]:02x});") + cmds.append("cmd_delay(1); // small delay") + + return cmds + + +def lmx2594_cmds(regs, dev_addr=0x2a, mask=0x01): + cmds = [] + + print(f"Reading register list file '{regs}'...") + + with open(regs, "r") as f: + for line in f: + line = line.strip() + if not line or line == "Address,Data": + continue + if line[0] == '#': + cmds.append(f"// {line[1:].strip()}") + + if line.startswith("# Delay"): + cmds.append("cmd_delay(10); // delay 300 ms") + + continue + + d = line.split(",") + addr = int(d[0], 0) + data = int(d[1], 0) + data_msb = (data >> 8) & 0xff + data_lsb = data & 0xff + + cmds.append(f"cmd_start(7'h{dev_addr:02x});") + cmds.append(f"cmd_wr(8'h{mask:02x}); // SPI transfer, CS mask {mask:#03x}") + cmds.append(f"cmd_wr(8'h{addr:02x}); // address {addr:#04x}") + cmds.append(f"cmd_wr(8'h{data_msb:02x}); // write {data:#06x}") + cmds.append(f"cmd_wr(8'h{data_lsb:02x});") + cmds.append("cmd_delay(1); // small delay") + + return cmds + + +def mux_cmds(val, dev_addr): + cmds = [] + cmds.append(f"cmd_start(7'h{dev_addr:02x});") + cmds.append(f"cmd_wr(8'h{val:02x});") + cmds.append("cmd_stop(); // I2C stop") + return cmds + + +def main(): + cmds = [] + + cmds.append("// Initial delay") + cmds.append("cmd_delay(6); // delay 30 ms") + + # PLLs for RF data converters + cmds.append("// Set mux to select I2C-SPI bridge on ZCU111") + cmds.extend(mux_cmds(0x20, 0x74)) + cmds.extend(mux_cmds(0x00, 0x75)) + + cmds.append("// Configure I2C-SPI bridge") + cmds.append("cmd_start(7'h2f);") + cmds.append("cmd_wr(8'hf0);") + cmds.append("cmd_wr(8'h00);") + cmds.append("cmd_start(7'h2f);") + cmds.append("cmd_wr(8'hf6);") + cmds.append("cmd_wr(8'h00);") + + cmds.extend(lmk04208_cmds("LMK04208_250.txt", 0x2f, 0x02)) + + cmds.extend(lmx2594_cmds("LMX2594_250_1000.txt", 0x2f, 0x0d)) + + cmds.append("// Clear I2C-SPI bridge interrupt") + cmds.append("cmd_start(7'h2f);") + cmds.append("cmd_wr(8'hf1);") + + # cmds.append("// Delay for PLL to lock") + # cmds.append("cmd_delay(12); // delay 300 ms") + + generate(cmds) + + +def generate(cmds=None, name=None, output=None): + if cmds is None: + raise Exception("Command list is required") + + if name is None: + name = "pll_i2c_init" + + if output is None: + output = name + ".sv" + + print(f"Generating PLL I2C init module {name}...") + + cmds = cmds.copy() + cmds.append("cmd_halt(); // end") + + cmd_str = "" + cmd_count = 0 + + for cmd in cmds: + if cmd.startswith('//'): + cmd_str += f" {cmd}\n" + else: + cmd_str += f" init_data[{cmd_count}] = {cmd}\n" + cmd_count += 1 + + t = Template(u"""// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2015-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * {{name}} + */ +module {{name}} # +( + parameter logic SIM_SPEEDUP = 1'b0 +) +( + input wire logic clk, + input wire logic rst, + + /* + * I2C master interface + */ + taxi_axis_if.src m_axis_cmd, + taxi_axis_if.src m_axis_tx, + + /* + * Status + */ + output wire logic busy, + + /* + * Configuration + */ + input wire logic start +); + +/* + +Generic module for I2C bus initialization. Good for use when multiple devices +on an I2C bus must be initialized on system start without intervention of a +general-purpose processor. + +Copy this file and change init_data and INIT_DATA_LEN as needed. + +This module can be used in two modes: simple device initialization, or multiple +device initialization. In multiple device mode, the same initialization sequence +can be performed on multiple different device addresses. + +To use single device mode, only use the start write to address and write data commands. +The module will generate the I2C commands in sequential order. Terminate the list +with a 0 entry. + +To use the multiple device mode, use the start data and start address block commands +to set up lists of initialization data and device addresses. The module enters +multiple device mode upon seeing a start data block command. The module stores the +offset of the start of the data block and then skips ahead until it reaches a start +address block command. The module will store the offset to the address block and +read the first address in the block. Then it will jump back to the data block +and execute it, substituting the stored address for each current address write +command. Upon reaching the start address block command, the module will read out the +next address and start again at the top of the data block. If the module encounters +a start data block command while looking for an address, then it will store a new data +offset and then look for a start address block command. Terminate the list with a 0 +entry. Normal address commands will operate normally inside a data block. + +Commands: + +00 0000000 : stop +00 0000001 : exit multiple device mode +00 0000011 : start write to current address +00 0001000 : start address block +00 0001001 : start data block +00 001dddd : delay 2**(16+d) cycles +00 1000001 : send I2C stop +01 aaaaaaa : start write to address +1 dddddddd : write 8-bit data + +Examples + +write 0x11223344 to register 0x0004 on device at 0x50 + +01 1010000 start write to 0x50 +1 00000000 write address 0x0004 +1 00000100 +1 00010001 write data 0x11223344 +1 00100010 +1 00110011 +1 01000100 +0 00000000 stop + +write 0x11223344 to register 0x0004 on devices at 0x50, 0x51, 0x52, and 0x53 + +00 0001001 start data block +00 0000011 start write to current address +1 00000000 write address 0x0004 +1 00000100 +1 00010001 write data 0x11223344 +1 00100010 +1 00110011 +1 01000100 +00 0001000 start address block +01 1010000 address 0x50 +01 1010001 address 0x51 +01 1010010 address 0x52 +01 1010011 address 0x53 +00 0000001 exit multi-dev mode +00 0000000 stop + +*/ + +// check configuration +if (m_axis_cmd.DATA_W < 12) + $fatal(0, "Command interface width must be at least 12 bits (instance %m)"); + +if (m_axis_tx.DATA_W != 8) + $fatal(0, "Data interface width must be 8 bits (instance %m)"); + +function [8:0] cmd_start(input [6:0] addr); + cmd_start = {2'b01, addr}; +endfunction + +function [8:0] cmd_wr(input [7:0] data); + cmd_wr = {1'b1, data}; +endfunction + +function [8:0] cmd_stop(); + cmd_stop = {2'b00, 7'b1000001}; +endfunction + +function [8:0] cmd_delay(input [3:0] d); + cmd_delay = {2'b00, 3'b001, d}; +endfunction + +function [8:0] cmd_halt(); + cmd_halt = 9'd0; +endfunction + +function [8:0] blk_start_data(); + blk_start_data = {2'b00, 7'b0001001}; +endfunction + +function [8:0] blk_start_addr(); + blk_start_addr = {2'b00, 7'b0001000}; +endfunction + +function [8:0] cmd_start_cur(); + cmd_start_cur = {2'b00, 7'b0000011}; +endfunction + +function [8:0] cmd_exit(); + cmd_exit = {2'b00, 7'b0000001}; +endfunction + +// init_data ROM +localparam INIT_DATA_LEN = {{cmd_count}}; + +reg [8:0] init_data [INIT_DATA_LEN-1:0]; + +initial begin +{{cmd_str-}} +end + +localparam [2:0] + STATE_IDLE = 3'd0, + STATE_RUN = 3'd1, + STATE_TABLE_1 = 3'd2, + STATE_TABLE_2 = 3'd3, + STATE_TABLE_3 = 3'd4; + +logic [2:0] state_reg = STATE_IDLE, state_next; + +localparam AW = $clog2(INIT_DATA_LEN); + +logic [8:0] init_data_reg = '0; + +logic [AW-1:0] address_reg = '0, address_next; +logic [AW-1:0] address_ptr_reg = '0, address_ptr_next; +logic [AW-1:0] data_ptr_reg = '0, data_ptr_next; + +logic [6:0] cur_address_reg = '0, cur_address_next; + +logic [31:0] delay_counter_reg = '0, delay_counter_next; + +logic [6:0] m_axis_cmd_address_reg = '0, m_axis_cmd_address_next; +logic m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next; +logic m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next; +logic m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next; +logic m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next; + +logic [7:0] m_axis_tx_tdata_reg = '0, m_axis_tx_tdata_next; +logic m_axis_tx_tvalid_reg = 1'b0, m_axis_tx_tvalid_next; + +logic start_flag_reg = 1'b0, start_flag_next; + +logic busy_reg = 1'b0; + +assign m_axis_cmd.tdata[6:0] = m_axis_cmd_address_reg; +assign m_axis_cmd.tdata[7] = m_axis_cmd_start_reg; +assign m_axis_cmd.tdata[8] = 1'b0; // read +assign m_axis_cmd.tdata[9] = m_axis_cmd_write_reg; +assign m_axis_cmd.tdata[10] = 1'b0; // write multi +assign m_axis_cmd.tdata[11] = m_axis_cmd_stop_reg; +assign m_axis_cmd.tvalid = m_axis_cmd_valid_reg; +assign m_axis_cmd.tlast = 1'b1; +assign m_axis_cmd.tid = '0; +assign m_axis_cmd.tdest = '0; +assign m_axis_cmd.tuser = '0; + +assign m_axis_tx.tdata = m_axis_tx_tdata_reg; +assign m_axis_tx.tvalid = m_axis_tx_tvalid_reg; +assign m_axis_tx.tlast = 1'b1; +assign m_axis_tx.tid = '0; +assign m_axis_tx.tdest = '0; +assign m_axis_tx.tuser = '0; + +assign busy = busy_reg; + +always_comb begin + state_next = STATE_IDLE; + + address_next = address_reg; + address_ptr_next = address_ptr_reg; + data_ptr_next = data_ptr_reg; + + cur_address_next = cur_address_reg; + + delay_counter_next = delay_counter_reg; + + m_axis_cmd_address_next = m_axis_cmd_address_reg; + m_axis_cmd_start_next = m_axis_cmd_start_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready); + m_axis_cmd_write_next = m_axis_cmd_write_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready); + m_axis_cmd_stop_next = m_axis_cmd_stop_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready); + m_axis_cmd_valid_next = m_axis_cmd_valid_reg && !m_axis_cmd.tready; + + m_axis_tx_tdata_next = m_axis_tx_tdata_reg; + m_axis_tx_tvalid_next = m_axis_tx_tvalid_reg && !m_axis_tx.tready; + + start_flag_next = start_flag_reg; + + if (m_axis_cmd.tvalid || m_axis_tx.tvalid) begin + // wait for output registers to clear + state_next = state_reg; + end else if (delay_counter_reg != 0) begin + // delay + delay_counter_next = delay_counter_reg - 1; + state_next = state_reg; + end else begin + case (state_reg) + STATE_IDLE: begin + // wait for start signal + if (!start_flag_reg && start) begin + address_next = '0; + start_flag_next = 1'b1; + state_next = STATE_RUN; + end else begin + state_next = STATE_IDLE; + end + end + STATE_RUN: begin + // process commands + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_tx_tdata_next = init_data_reg[7:0]; + m_axis_tx_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:4] == 5'b00001) begin + // delay + if (SIM_SPEEDUP) begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]); + end else begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]+16); + end + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_RUN; + end + end + STATE_TABLE_1: begin + // find address table start + if (init_data_reg == 9'b000001000) begin + // address table start + address_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end + end + STATE_TABLE_2: begin + // find next address + if (init_data_reg[8:7] == 2'b01) begin + // write address command + // store address and move to data table + cur_address_next = init_data_reg[6:0]; + address_ptr_next = address_reg + 1; + address_next = data_ptr_reg; + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end + end + STATE_TABLE_3: begin + // process data table with selected address + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_tx_tdata_next = init_data_reg[7:0]; + m_axis_tx_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000000011) begin + // write current address + m_axis_cmd_address_next = cur_address_reg; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg[8:4] == 5'b00001) begin + // delay + if (SIM_SPEEDUP) begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]); + end else begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]+16); + end + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'b000001000) begin + // address table start + address_next = address_ptr_reg; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_3; + end + end + default: begin + // invalid state + state_next = STATE_IDLE; + end + endcase + end +end + +always_ff @(posedge clk) begin + state_reg <= state_next; + + // read init_data ROM + init_data_reg <= init_data[address_next]; + + address_reg <= address_next; + address_ptr_reg <= address_ptr_next; + data_ptr_reg <= data_ptr_next; + + cur_address_reg <= cur_address_next; + + delay_counter_reg <= delay_counter_next; + + m_axis_cmd_address_reg <= m_axis_cmd_address_next; + m_axis_cmd_start_reg <= m_axis_cmd_start_next; + m_axis_cmd_write_reg <= m_axis_cmd_write_next; + m_axis_cmd_stop_reg <= m_axis_cmd_stop_next; + m_axis_cmd_valid_reg <= m_axis_cmd_valid_next; + + m_axis_tx_tdata_reg <= m_axis_tx_tdata_next; + m_axis_tx_tvalid_reg <= m_axis_tx_tvalid_next; + + start_flag_reg <= start && start_flag_next; + + busy_reg <= (state_reg != STATE_IDLE); + + if (rst) begin + state_reg <= STATE_IDLE; + + init_data_reg <= '0; + + address_reg <= '0; + address_ptr_reg <= '0; + data_ptr_reg <= '0; + + cur_address_reg <= '0; + + delay_counter_reg <= '0; + + m_axis_cmd_valid_reg <= 1'b0; + + m_axis_tx_tvalid_reg <= 1'b0; + + start_flag_reg <= 1'b0; + + busy_reg <= 1'b0; + end +end + +endmodule + +`resetall +""") + + print(f"Writing file '{output}'...") + + with open(output, 'w') as f: + f.write(t.render( + cmd_str=cmd_str, + cmd_count=cmd_count, + name=name + )) + f.flush() + + print("Done") + + +if __name__ == "__main__": + main() diff --git a/src/eth/example/ZCU111/fpga/pll/pll_i2c_init.sv b/src/eth/example/ZCU111/fpga/pll/pll_i2c_init.sv new file mode 100644 index 0000000..2215bff --- /dev/null +++ b/src/eth/example/ZCU111/fpga/pll/pll_i2c_init.sv @@ -0,0 +1,1083 @@ +// SPDX-License-Identifier: CERN-OHL-S-2.0 +/* + +Copyright (c) 2015-2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * pll_i2c_init + */ +module pll_i2c_init # +( + parameter logic SIM_SPEEDUP = 1'b0 +) +( + input wire logic clk, + input wire logic rst, + + /* + * I2C master interface + */ + taxi_axis_if.src m_axis_cmd, + taxi_axis_if.src m_axis_tx, + + /* + * Status + */ + output wire logic busy, + + /* + * Configuration + */ + input wire logic start +); + +/* + +Generic module for I2C bus initialization. Good for use when multiple devices +on an I2C bus must be initialized on system start without intervention of a +general-purpose processor. + +Copy this file and change init_data and INIT_DATA_LEN as needed. + +This module can be used in two modes: simple device initialization, or multiple +device initialization. In multiple device mode, the same initialization sequence +can be performed on multiple different device addresses. + +To use single device mode, only use the start write to address and write data commands. +The module will generate the I2C commands in sequential order. Terminate the list +with a 0 entry. + +To use the multiple device mode, use the start data and start address block commands +to set up lists of initialization data and device addresses. The module enters +multiple device mode upon seeing a start data block command. The module stores the +offset of the start of the data block and then skips ahead until it reaches a start +address block command. The module will store the offset to the address block and +read the first address in the block. Then it will jump back to the data block +and execute it, substituting the stored address for each current address write +command. Upon reaching the start address block command, the module will read out the +next address and start again at the top of the data block. If the module encounters +a start data block command while looking for an address, then it will store a new data +offset and then look for a start address block command. Terminate the list with a 0 +entry. Normal address commands will operate normally inside a data block. + +Commands: + +00 0000000 : stop +00 0000001 : exit multiple device mode +00 0000011 : start write to current address +00 0001000 : start address block +00 0001001 : start data block +00 001dddd : delay 2**(16+d) cycles +00 1000001 : send I2C stop +01 aaaaaaa : start write to address +1 dddddddd : write 8-bit data + +Examples + +write 0x11223344 to register 0x0004 on device at 0x50 + +01 1010000 start write to 0x50 +1 00000000 write address 0x0004 +1 00000100 +1 00010001 write data 0x11223344 +1 00100010 +1 00110011 +1 01000100 +0 00000000 stop + +write 0x11223344 to register 0x0004 on devices at 0x50, 0x51, 0x52, and 0x53 + +00 0001001 start data block +00 0000011 start write to current address +1 00000000 write address 0x0004 +1 00000100 +1 00010001 write data 0x11223344 +1 00100010 +1 00110011 +1 01000100 +00 0001000 start address block +01 1010000 address 0x50 +01 1010001 address 0x51 +01 1010010 address 0x52 +01 1010011 address 0x53 +00 0000001 exit multi-dev mode +00 0000000 stop + +*/ + +// check configuration +if (m_axis_cmd.DATA_W < 12) + $fatal(0, "Command interface width must be at least 12 bits (instance %m)"); + +if (m_axis_tx.DATA_W != 8) + $fatal(0, "Data interface width must be 8 bits (instance %m)"); + +function [8:0] cmd_start(input [6:0] addr); + cmd_start = {2'b01, addr}; +endfunction + +function [8:0] cmd_wr(input [7:0] data); + cmd_wr = {1'b1, data}; +endfunction + +function [8:0] cmd_stop(); + cmd_stop = {2'b00, 7'b1000001}; +endfunction + +function [8:0] cmd_delay(input [3:0] d); + cmd_delay = {2'b00, 3'b001, d}; +endfunction + +function [8:0] cmd_halt(); + cmd_halt = 9'd0; +endfunction + +function [8:0] blk_start_data(); + blk_start_data = {2'b00, 7'b0001001}; +endfunction + +function [8:0] blk_start_addr(); + blk_start_addr = {2'b00, 7'b0001000}; +endfunction + +function [8:0] cmd_start_cur(); + cmd_start_cur = {2'b00, 7'b0000011}; +endfunction + +function [8:0] cmd_exit(); + cmd_exit = {2'b00, 7'b0000001}; +endfunction + +// init_data ROM +localparam INIT_DATA_LEN = 428; + +reg [8:0] init_data [INIT_DATA_LEN-1:0]; + +initial begin + // Initial delay + init_data[0] = cmd_delay(6); // delay 30 ms + // Set mux to select I2C-SPI bridge on ZCU111 + init_data[1] = cmd_start(7'h74); + init_data[2] = cmd_wr(8'h20); + init_data[3] = cmd_stop(); // I2C stop + init_data[4] = cmd_start(7'h75); + init_data[5] = cmd_wr(8'h00); + init_data[6] = cmd_stop(); // I2C stop + // Configure I2C-SPI bridge + init_data[7] = cmd_start(7'h2f); + init_data[8] = cmd_wr(8'hf0); + init_data[9] = cmd_wr(8'h00); + init_data[10] = cmd_start(7'h2f); + init_data[11] = cmd_wr(8'hf6); + init_data[12] = cmd_wr(8'h00); + // Configuration for LMK04208 PLL + // PLL1 + // CLKin0 = 12.8 MHz TCXO + // CLKin1 = 10 MHz + // CLKin0 R = 800 + // CLKin1 R = 625 + // PFD = in0 / R0 = in1 / R1 = 16 kHz + // N1 = 7680 + // VCO = PFD * N1 = 122.88 MHz + // Ext VCO is 122.88 MHz + // PLL2 + // 122.88 MHz from ext VCO + // VCO range 2750 - 3072 MHz + // R2 = 384 + // VCODIV = 3 + // N2 P = 5 + // N2 = 625 + // PFD = 122.88 / R2 = 0.32 + // VCO = PFD * VCODIV * P * N2 = 3000 + // VCO/3/4 = 250 MHz + // VCO/3/100 = 10 MHz + // VCO/3/512 = 1.953125 MHz + // CLKout0: FPGA SYSREF + // CLKout1: DAC 228 SYSREF + // CLKout2: FPGA REFCLK + // CLKout3: SYNC_2594 + // CLKout4: REFCLK_2594 + // CLKout5: SMA + // Reset + init_data[13] = cmd_start(7'h2f); + init_data[14] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[15] = cmd_wr(8'h00); // write 0x00020000 + init_data[16] = cmd_wr(8'h02); + init_data[17] = cmd_wr(8'h00); + init_data[18] = cmd_wr(8'h00); + init_data[19] = cmd_delay(1); // small delay + init_data[20] = cmd_start(7'h2f); + init_data[21] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[22] = cmd_wr(8'h00); // write 0x00000000 + init_data[23] = cmd_wr(8'h00); + init_data[24] = cmd_wr(8'h00); + init_data[25] = cmd_wr(8'h00); + init_data[26] = cmd_delay(1); // small delay + // CLKout0 DDLY 10, DIV 512 + init_data[27] = cmd_start(7'h2f); + init_data[28] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[29] = cmd_wr(8'h00); // write 0x00284000 + init_data[30] = cmd_wr(8'h28); + init_data[31] = cmd_wr(8'h40); + init_data[32] = cmd_wr(8'h00); + init_data[33] = cmd_delay(1); // small delay + // CLKout1 DDLY 10, DIV 512 + init_data[34] = cmd_start(7'h2f); + init_data[35] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[36] = cmd_wr(8'h00); // write 0x00284001 + init_data[37] = cmd_wr(8'h28); + init_data[38] = cmd_wr(8'h40); + init_data[39] = cmd_wr(8'h01); + init_data[40] = cmd_delay(1); // small delay + // CLKout2 DDLY 10, DIV 4 + init_data[41] = cmd_start(7'h2f); + init_data[42] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[43] = cmd_wr(8'h00); // write 0x00280082 + init_data[44] = cmd_wr(8'h28); + init_data[45] = cmd_wr(8'h00); + init_data[46] = cmd_wr(8'h82); + init_data[47] = cmd_delay(1); // small delay + // CLKout3 DDLY 10, DIV 512 + init_data[48] = cmd_start(7'h2f); + init_data[49] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[50] = cmd_wr(8'h00); // write 0x00284003 + init_data[51] = cmd_wr(8'h28); + init_data[52] = cmd_wr(8'h40); + init_data[53] = cmd_wr(8'h03); + init_data[54] = cmd_delay(1); // small delay + // CLKout4 DDLY 10, DIV 4 + init_data[55] = cmd_start(7'h2f); + init_data[56] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[57] = cmd_wr(8'h00); // write 0x00280084 + init_data[58] = cmd_wr(8'h28); + init_data[59] = cmd_wr(8'h00); + init_data[60] = cmd_wr(8'h84); + init_data[61] = cmd_delay(1); // small delay + // CLKout5 DDLY 10, DIV 100 + init_data[62] = cmd_start(7'h2f); + init_data[63] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[64] = cmd_wr(8'h00); // write 0x00280c85 + init_data[65] = cmd_wr(8'h28); + init_data[66] = cmd_wr(8'h0c); + init_data[67] = cmd_wr(8'h85); + init_data[68] = cmd_delay(1); // small delay + // CLKout0 LVDS, CLKout1 LVDS + init_data[69] = cmd_start(7'h2f); + init_data[70] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[71] = cmd_wr(8'h01); // write 0x01100006 + init_data[72] = cmd_wr(8'h10); + init_data[73] = cmd_wr(8'h00); + init_data[74] = cmd_wr(8'h06); + init_data[75] = cmd_delay(1); // small delay + // CLKout2 LVDS, CLKout3 LVDS + init_data[76] = cmd_start(7'h2f); + init_data[77] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[78] = cmd_wr(8'h01); // write 0x01100007 + init_data[79] = cmd_wr(8'h10); + init_data[80] = cmd_wr(8'h00); + init_data[81] = cmd_wr(8'h07); + init_data[82] = cmd_delay(1); // small delay + // CLKout4 LVDS, CLKout5 LVCMOS + init_data[83] = cmd_start(7'h2f); + init_data[84] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[85] = cmd_wr(8'h06); // write 0x06010008 + init_data[86] = cmd_wr(8'h01); + init_data[87] = cmd_wr(8'h00); + init_data[88] = cmd_wr(8'h08); + init_data[89] = cmd_delay(1); // small delay + // RSVD + init_data[90] = cmd_start(7'h2f); + init_data[91] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[92] = cmd_wr(8'h55); // write 0x55555549 + init_data[93] = cmd_wr(8'h55); + init_data[94] = cmd_wr(8'h55); + init_data[95] = cmd_wr(8'h49); + init_data[96] = cmd_delay(1); // small delay + // OSCout off, VCO div 3 + init_data[97] = cmd_start(7'h2f); + init_data[98] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[99] = cmd_wr(8'h10); // write 0x1000530a + init_data[100] = cmd_wr(8'h00); + init_data[101] = cmd_wr(8'h53); + init_data[102] = cmd_wr(8'h0a); + init_data[103] = cmd_delay(1); // small delay + // MODE 0, sync on, SYNC_TYPE input with pull-up, no xtal + init_data[104] = cmd_start(7'h2f); + init_data[105] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[106] = cmd_wr(8'h04); // write 0x0400200b + init_data[107] = cmd_wr(8'h00); + init_data[108] = cmd_wr(8'h20); + init_data[109] = cmd_wr(8'h0b); + init_data[110] = cmd_delay(1); // small delay + // LD_MUX PLL1&PLL2, SYNC_PLL2_DLD on, EN_TRACK on, holdover disable + init_data[111] = cmd_start(7'h2f); + init_data[112] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[113] = cmd_wr(8'h1b); // write 0x1b8c016c + init_data[114] = cmd_wr(8'h8c); + init_data[115] = cmd_wr(8'h01); + init_data[116] = cmd_wr(8'h6c); + init_data[117] = cmd_delay(1); // small delay + // HOLDOVER_MUX readback, DISABLE_DLD1_DET on, CLKin_SELECT_MODE CLKin0, EN_CLKin0 + init_data[118] = cmd_start(7'h2f); + init_data[119] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[120] = cmd_wr(8'h3b); // write 0x3b00802d + init_data[121] = cmd_wr(8'h00); + init_data[122] = cmd_wr(8'h80); + init_data[123] = cmd_wr(8'h2d); + init_data[124] = cmd_delay(1); // small delay + // LOS_TIMEOUT 1200 ns, CLKinX_BUF_TYPE Bipolar, DAC_HIGH_TRIP 63, DAC_LOW_TRIP 0 + init_data[125] = cmd_start(7'h2f); + init_data[126] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[127] = cmd_wr(8'h00); // write 0x000fc00e + init_data[128] = cmd_wr(8'h0f); + init_data[129] = cmd_wr(8'hc0); + init_data[130] = cmd_wr(8'h0e); + init_data[131] = cmd_delay(1); // small delay + // MAN_DAC 0, EN_MAN_DAC auto + init_data[132] = cmd_start(7'h2f); + init_data[133] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[134] = cmd_wr(8'h00); // write 0x0000000f + init_data[135] = cmd_wr(8'h00); + init_data[136] = cmd_wr(8'h00); + init_data[137] = cmd_wr(8'h0f); + init_data[138] = cmd_delay(1); // small delay + // XTAL_LVL 1.65 Vpp + init_data[139] = cmd_start(7'h2f); + init_data[140] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[141] = cmd_wr(8'h01); // write 0x01550410 + init_data[142] = cmd_wr(8'h55); + init_data[143] = cmd_wr(8'h04); + init_data[144] = cmd_wr(8'h10); + init_data[145] = cmd_delay(1); // small delay + // PLL2_C4_LF 10pF, PLL2_C3_LF 10 pF, PLL2_R4_LF 200 ohm, PLL2_R3_LF 200 ohm, PLL1_N_DLY 0 ps, PLL1_R_DLY 0 ps, PLL1_WND_SIZE 5.5 ns + init_data[146] = cmd_start(7'h2f); + init_data[147] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[148] = cmd_wr(8'h00); // write 0x00000018 + init_data[149] = cmd_wr(8'h00); + init_data[150] = cmd_wr(8'h00); + init_data[151] = cmd_wr(8'h18); + init_data[152] = cmd_delay(1); // small delay + // DAC_CLK_DIV 1023, PLL1_DLD_CNT 16383 + init_data[153] = cmd_start(7'h2f); + init_data[154] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[155] = cmd_wr(8'hff); // write 0xffcfffd9 + init_data[156] = cmd_wr(8'hcf); + init_data[157] = cmd_wr(8'hff); + init_data[158] = cmd_wr(8'hd9); + init_data[159] = cmd_delay(1); // small delay + // PLL2_WND_SIZE 2, EN_PLL2_REF_2X off, PLL2_CP_POL neg, PLL2_CP_GAIN 100, PLL2_DLD_CNT 16383, PLL2_CP_TRI off + init_data[160] = cmd_start(7'h2f); + init_data[161] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[162] = cmd_wr(8'h83); // write 0x83afffda + init_data[163] = cmd_wr(8'haf); + init_data[164] = cmd_wr(8'hff); + init_data[165] = cmd_wr(8'hda); + init_data[166] = cmd_delay(1); // small delay + // PLL1_CP_POL pos, PLL1_CP_GAIN 100, CLKinX_PreR_DIV 1, PLL1_R 800, PLL1_CP_TRI off + init_data[167] = cmd_start(7'h2f); + init_data[168] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[169] = cmd_wr(8'h10); // write 0x1000c81b + init_data[170] = cmd_wr(8'h00); + init_data[171] = cmd_wr(8'hc8); + init_data[172] = cmd_wr(8'h1b); + init_data[173] = cmd_delay(1); // small delay + // PLL2_R 384, PLL1_N 7680 + init_data[174] = cmd_start(7'h2f); + init_data[175] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[176] = cmd_wr(8'h18); // write 0x1807801c + init_data[177] = cmd_wr(8'h07); + init_data[178] = cmd_wr(8'h80); + init_data[179] = cmd_wr(8'h1c); + init_data[180] = cmd_delay(1); // small delay + // OSCin_FREQ 63-127, PLL2_FAST_PDF under 100, PLL2_N_CAL 625 + init_data[181] = cmd_start(7'h2f); + init_data[182] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[183] = cmd_wr(8'h01); // write 0x01004e3d + init_data[184] = cmd_wr(8'h00); + init_data[185] = cmd_wr(8'h4e); + init_data[186] = cmd_wr(8'h3d); + init_data[187] = cmd_delay(1); // small delay + // PLL2_P 5, PLL2_N 625 + init_data[188] = cmd_start(7'h2f); + init_data[189] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[190] = cmd_wr(8'h05); // write 0x05004e3e + init_data[191] = cmd_wr(8'h00); + init_data[192] = cmd_wr(8'h4e); + init_data[193] = cmd_wr(8'h3e); + init_data[194] = cmd_delay(1); // small delay + // READBACK_LE 0 + init_data[195] = cmd_start(7'h2f); + init_data[196] = cmd_wr(8'h02); // SPI transfer, CS mask 0x2 + init_data[197] = cmd_wr(8'h00); // write 0x0000001f + init_data[198] = cmd_wr(8'h00); + init_data[199] = cmd_wr(8'h00); + init_data[200] = cmd_wr(8'h1f); + init_data[201] = cmd_delay(1); // small delay + // Configuration for LMX2594 PLL + // OSCin = 250 MHz + // VCO range 7.5 - 15 GHz + // R_PRE = 1 + // R = 1 + // PFD = OSCin / (R_PRE * R) = 250 MHz + // N = 32 + // VCO = PFD * N = 8 GHz + // VCO / 8 = 1 GHz + // Reset + init_data[202] = cmd_start(7'h2f); + init_data[203] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[204] = cmd_wr(8'h00); // address 0x00 + init_data[205] = cmd_wr(8'h24); // write 0x2412 + init_data[206] = cmd_wr(8'h12); + init_data[207] = cmd_delay(1); // small delay + init_data[208] = cmd_start(7'h2f); + init_data[209] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[210] = cmd_wr(8'h00); // address 0x00 + init_data[211] = cmd_wr(8'h24); // write 0x2410 + init_data[212] = cmd_wr(8'h10); + init_data[213] = cmd_delay(1); // small delay + // QUICK_RECAL_EN: 0 + // VCO_CAPCTRL_STRT: 0 + init_data[214] = cmd_start(7'h2f); + init_data[215] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[216] = cmd_wr(8'h4e); // address 0x4e + init_data[217] = cmd_wr(8'h00); // write 0x0001 + init_data[218] = cmd_wr(8'h01); + init_data[219] = cmd_delay(1); // small delay + // CHDIV: 3 (8) + init_data[220] = cmd_start(7'h2f); + init_data[221] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[222] = cmd_wr(8'h4b); // address 0x4b + init_data[223] = cmd_wr(8'h08); // write 0x08c0 + init_data[224] = cmd_wr(8'hc0); + init_data[225] = cmd_delay(1); // small delay + // MASH_RST_COUNT: 50000 (0xc350) + init_data[226] = cmd_start(7'h2f); + init_data[227] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[228] = cmd_wr(8'h46); // address 0x46 + init_data[229] = cmd_wr(8'hc3); // write 0xc350 + init_data[230] = cmd_wr(8'h50); + init_data[231] = cmd_delay(1); // small delay + // MASH_RST_COUNT: 50000 (0xc350) + init_data[232] = cmd_start(7'h2f); + init_data[233] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[234] = cmd_wr(8'h45); // address 0x45 + init_data[235] = cmd_wr(8'h00); // write 0x0000 + init_data[236] = cmd_wr(8'h00); + init_data[237] = cmd_delay(1); // small delay + // LD_DELAY: 1000 (0x3e8) + init_data[238] = cmd_start(7'h2f); + init_data[239] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[240] = cmd_wr(8'h3c); // address 0x3c + init_data[241] = cmd_wr(8'h03); // write 0x03e8 + init_data[242] = cmd_wr(8'he8); + init_data[243] = cmd_delay(1); // small delay + // LD_TYPE: 1 + init_data[244] = cmd_start(7'h2f); + init_data[245] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[246] = cmd_wr(8'h3b); // address 0x3b + init_data[247] = cmd_wr(8'h00); // write 0x0001 + init_data[248] = cmd_wr(8'h01); + init_data[249] = cmd_delay(1); // small delay + // INPIN_IGNORE: 1 + // INPIN_HYST: 0 + // INPIN_LVL: 0 + // INPIN_FMT: 0 + init_data[250] = cmd_start(7'h2f); + init_data[251] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[252] = cmd_wr(8'h3a); // address 0x3a + init_data[253] = cmd_wr(8'h80); // write 0x8001 + init_data[254] = cmd_wr(8'h01); + init_data[255] = cmd_delay(1); // small delay + // OUTB_MUX: 0 (ch div) + init_data[256] = cmd_start(7'h2f); + init_data[257] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[258] = cmd_wr(8'h2e); // address 0x2e + init_data[259] = cmd_wr(8'h07); // write 0x07fc + init_data[260] = cmd_wr(8'hfc); + init_data[261] = cmd_delay(1); // small delay + // OUTA_MUX: 0 (ch div) + // OUT_ISET: 0 (max) + // OUTB_PWR: 31 (0x1f) + init_data[262] = cmd_start(7'h2f); + init_data[263] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[264] = cmd_wr(8'h2d); // address 0x2d + init_data[265] = cmd_wr(8'hc0); // write 0xc0df + init_data[266] = cmd_wr(8'hdf); + init_data[267] = cmd_delay(1); // small delay + // OUTA_PWR: 31 (0x1f) + // OUTB_PD: 0 + // OUTA_PD: 0 + // MASH_RESET_N: 0 + // MASH_ORDER: 0 + init_data[268] = cmd_start(7'h2f); + init_data[269] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[270] = cmd_wr(8'h2c); // address 0x2c + init_data[271] = cmd_wr(8'h1f); // write 0x1f00 + init_data[272] = cmd_wr(8'h00); + init_data[273] = cmd_delay(1); // small delay + // PLL_NUM: 0 + init_data[274] = cmd_start(7'h2f); + init_data[275] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[276] = cmd_wr(8'h2b); // address 0x2b + init_data[277] = cmd_wr(8'h00); // write 0x0000 + init_data[278] = cmd_wr(8'h00); + init_data[279] = cmd_delay(1); // small delay + // PLL_NUM: 0 + init_data[280] = cmd_start(7'h2f); + init_data[281] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[282] = cmd_wr(8'h2a); // address 0x2a + init_data[283] = cmd_wr(8'h00); // write 0x0000 + init_data[284] = cmd_wr(8'h00); + init_data[285] = cmd_delay(1); // small delay + // MASH_SEED: 0 + init_data[286] = cmd_start(7'h2f); + init_data[287] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[288] = cmd_wr(8'h29); // address 0x29 + init_data[289] = cmd_wr(8'h00); // write 0x0000 + init_data[290] = cmd_wr(8'h00); + init_data[291] = cmd_delay(1); // small delay + // MASH_SEED: 0 + init_data[292] = cmd_start(7'h2f); + init_data[293] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[294] = cmd_wr(8'h28); // address 0x28 + init_data[295] = cmd_wr(8'h00); // write 0x0000 + init_data[296] = cmd_wr(8'h00); + init_data[297] = cmd_delay(1); // small delay + // PLL_DEN: '1 + init_data[298] = cmd_start(7'h2f); + init_data[299] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[300] = cmd_wr(8'h27); // address 0x27 + init_data[301] = cmd_wr(8'hff); // write 0xffff + init_data[302] = cmd_wr(8'hff); + init_data[303] = cmd_delay(1); // small delay + // PLL_DEN: '1 + init_data[304] = cmd_start(7'h2f); + init_data[305] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[306] = cmd_wr(8'h26); // address 0x26 + init_data[307] = cmd_wr(8'hff); // write 0xffff + init_data[308] = cmd_wr(8'hff); + init_data[309] = cmd_delay(1); // small delay + // MASH_SEED_EN: 0 + // PFD_DLY_SEL: 2 + init_data[310] = cmd_start(7'h2f); + init_data[311] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[312] = cmd_wr(8'h25); // address 0x25 + init_data[313] = cmd_wr(8'h02); // write 0x0204 + init_data[314] = cmd_wr(8'h04); + init_data[315] = cmd_delay(1); // small delay + // PLL_N: 32 (0x20) + init_data[316] = cmd_start(7'h2f); + init_data[317] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[318] = cmd_wr(8'h24); // address 0x24 + init_data[319] = cmd_wr(8'h00); // write 0x0020 + init_data[320] = cmd_wr(8'h20); + init_data[321] = cmd_delay(1); // small delay + // PLL_N: 32 (0x20) + init_data[322] = cmd_start(7'h2f); + init_data[323] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[324] = cmd_wr(8'h22); // address 0x22 + init_data[325] = cmd_wr(8'h00); // write 0x0000 + init_data[326] = cmd_wr(8'h00); + init_data[327] = cmd_delay(1); // small delay + // CHDIV_DIV2: 1 + init_data[328] = cmd_start(7'h2f); + init_data[329] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[330] = cmd_wr(8'h1f); // address 0x1f + init_data[331] = cmd_wr(8'h43); // write 0x43ec + init_data[332] = cmd_wr(8'hec); + init_data[333] = cmd_delay(1); // small delay + // VCO_SEL: 7 (VCO7) + // VCO_SEL_FORCE: 0 + init_data[334] = cmd_start(7'h2f); + init_data[335] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[336] = cmd_wr(8'h14); // address 0x14 + init_data[337] = cmd_wr(8'hf8); // write 0xf848 + init_data[338] = cmd_wr(8'h48); + init_data[339] = cmd_delay(1); // small delay + // VCO_CAPCTRL: 183 (0xb7) + init_data[340] = cmd_start(7'h2f); + init_data[341] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[342] = cmd_wr(8'h13); // address 0x13 + init_data[343] = cmd_wr(8'h27); // write 0x27b7 + init_data[344] = cmd_wr(8'hb7); + init_data[345] = cmd_delay(1); // small delay + // 18,0x0000 + // VCO_DACISET_STRT: 250 (0xfa) + init_data[346] = cmd_start(7'h2f); + init_data[347] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[348] = cmd_wr(8'h11); // address 0x11 + init_data[349] = cmd_wr(8'h00); // write 0x00fa + init_data[350] = cmd_wr(8'hfa); + init_data[351] = cmd_delay(1); // small delay + // VCO_DACISET: 128 (0x80) + init_data[352] = cmd_start(7'h2f); + init_data[353] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[354] = cmd_wr(8'h10); // address 0x10 + init_data[355] = cmd_wr(8'h00); // write 0x0080 + init_data[356] = cmd_wr(8'h80); + init_data[357] = cmd_delay(1); // small delay + // 15,0x0000 + // CPG: 7 + init_data[358] = cmd_start(7'h2f); + init_data[359] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[360] = cmd_wr(8'h0e); // address 0x0e + init_data[361] = cmd_wr(8'h1e); // write 0x1e70 + init_data[362] = cmd_wr(8'h70); + init_data[363] = cmd_delay(1); // small delay + // PLL_R_PRE: 1 + init_data[364] = cmd_start(7'h2f); + init_data[365] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[366] = cmd_wr(8'h0c); // address 0x0c + init_data[367] = cmd_wr(8'h50); // write 0x5001 + init_data[368] = cmd_wr(8'h01); + init_data[369] = cmd_delay(1); // small delay + // PLL_R: 1 + init_data[370] = cmd_start(7'h2f); + init_data[371] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[372] = cmd_wr(8'h0b); // address 0x0b + init_data[373] = cmd_wr(8'h00); // write 0x0018 + init_data[374] = cmd_wr(8'h18); + init_data[375] = cmd_delay(1); // small delay + // MULT: 1 (bypass) + init_data[376] = cmd_start(7'h2f); + init_data[377] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[378] = cmd_wr(8'h0a); // address 0x0a + init_data[379] = cmd_wr(8'h10); // write 0x10d8 + init_data[380] = cmd_wr(8'hd8); + init_data[381] = cmd_delay(1); // small delay + // OSC_2X: 0 + init_data[382] = cmd_start(7'h2f); + init_data[383] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[384] = cmd_wr(8'h09); // address 0x09 + init_data[385] = cmd_wr(8'h06); // write 0x0604 + init_data[386] = cmd_wr(8'h04); + init_data[387] = cmd_delay(1); // small delay + // VCO_DACISET_FORCE: 0 + // VCO_CAPCTRL_FORCE: 0 + init_data[388] = cmd_start(7'h2f); + init_data[389] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[390] = cmd_wr(8'h08); // address 0x08 + init_data[391] = cmd_wr(8'h20); // write 0x2000 + init_data[392] = cmd_wr(8'h00); + init_data[393] = cmd_delay(1); // small delay + // OUT_FORCE: 0 + init_data[394] = cmd_start(7'h2f); + init_data[395] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[396] = cmd_wr(8'h07); // address 0x07 + init_data[397] = cmd_wr(8'h00); // write 0x00b2 + init_data[398] = cmd_wr(8'hb2); + init_data[399] = cmd_delay(1); // small delay + // ACAL_CMP_DLY: 10 + init_data[400] = cmd_start(7'h2f); + init_data[401] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[402] = cmd_wr(8'h04); // address 0x04 + init_data[403] = cmd_wr(8'h0a); // write 0x0a43 + init_data[404] = cmd_wr(8'h43); + init_data[405] = cmd_delay(1); // small delay + // CAL_CLK_DIV: 3 (div 8) + init_data[406] = cmd_start(7'h2f); + init_data[407] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[408] = cmd_wr(8'h01); // address 0x01 + init_data[409] = cmd_wr(8'h08); // write 0x080b + init_data[410] = cmd_wr(8'h0b); + init_data[411] = cmd_delay(1); // small delay + // FCAL_HPFD_ADJ: 3 (PFD > 200 MHz) + // FCAL_LPFD_ADJ: 0 (PFD > 10 MHz) + // FCAL_EN: 0 + // MUXOUT_LD_SEL: 0 (readback) + // RESET: 0 + // POWERDOWN: 0 + init_data[412] = cmd_start(7'h2f); + init_data[413] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[414] = cmd_wr(8'h00); // address 0x00 + init_data[415] = cmd_wr(8'h25); // write 0x2590 + init_data[416] = cmd_wr(8'h90); + init_data[417] = cmd_delay(1); // small delay + // Delay 10 msec + init_data[418] = cmd_delay(10); // delay 300 ms + // FCAL_HPFD_ADJ: 3 (PFD > 200 MHz) + // FCAL_LPFD_ADJ: 0 (PFD > 10 MHz) + // FCAL_EN: 1 + // MUXOUT_LD_SEL: 1 (LD) + // RESET: 0 + // POWERDOWN: 0 + init_data[419] = cmd_start(7'h2f); + init_data[420] = cmd_wr(8'h0d); // SPI transfer, CS mask 0xd + init_data[421] = cmd_wr(8'h00); // address 0x00 + init_data[422] = cmd_wr(8'h25); // write 0x259c + init_data[423] = cmd_wr(8'h9c); + init_data[424] = cmd_delay(1); // small delay + // Clear I2C-SPI bridge interrupt + init_data[425] = cmd_start(7'h2f); + init_data[426] = cmd_wr(8'hf1); + init_data[427] = cmd_halt(); // end +end + +localparam [2:0] + STATE_IDLE = 3'd0, + STATE_RUN = 3'd1, + STATE_TABLE_1 = 3'd2, + STATE_TABLE_2 = 3'd3, + STATE_TABLE_3 = 3'd4; + +logic [2:0] state_reg = STATE_IDLE, state_next; + +localparam AW = $clog2(INIT_DATA_LEN); + +logic [8:0] init_data_reg = '0; + +logic [AW-1:0] address_reg = '0, address_next; +logic [AW-1:0] address_ptr_reg = '0, address_ptr_next; +logic [AW-1:0] data_ptr_reg = '0, data_ptr_next; + +logic [6:0] cur_address_reg = '0, cur_address_next; + +logic [31:0] delay_counter_reg = '0, delay_counter_next; + +logic [6:0] m_axis_cmd_address_reg = '0, m_axis_cmd_address_next; +logic m_axis_cmd_start_reg = 1'b0, m_axis_cmd_start_next; +logic m_axis_cmd_write_reg = 1'b0, m_axis_cmd_write_next; +logic m_axis_cmd_stop_reg = 1'b0, m_axis_cmd_stop_next; +logic m_axis_cmd_valid_reg = 1'b0, m_axis_cmd_valid_next; + +logic [7:0] m_axis_tx_tdata_reg = '0, m_axis_tx_tdata_next; +logic m_axis_tx_tvalid_reg = 1'b0, m_axis_tx_tvalid_next; + +logic start_flag_reg = 1'b0, start_flag_next; + +logic busy_reg = 1'b0; + +assign m_axis_cmd.tdata[6:0] = m_axis_cmd_address_reg; +assign m_axis_cmd.tdata[7] = m_axis_cmd_start_reg; +assign m_axis_cmd.tdata[8] = 1'b0; // read +assign m_axis_cmd.tdata[9] = m_axis_cmd_write_reg; +assign m_axis_cmd.tdata[10] = 1'b0; // write multi +assign m_axis_cmd.tdata[11] = m_axis_cmd_stop_reg; +assign m_axis_cmd.tvalid = m_axis_cmd_valid_reg; +assign m_axis_cmd.tlast = 1'b1; +assign m_axis_cmd.tid = '0; +assign m_axis_cmd.tdest = '0; +assign m_axis_cmd.tuser = '0; + +assign m_axis_tx.tdata = m_axis_tx_tdata_reg; +assign m_axis_tx.tvalid = m_axis_tx_tvalid_reg; +assign m_axis_tx.tlast = 1'b1; +assign m_axis_tx.tid = '0; +assign m_axis_tx.tdest = '0; +assign m_axis_tx.tuser = '0; + +assign busy = busy_reg; + +always_comb begin + state_next = STATE_IDLE; + + address_next = address_reg; + address_ptr_next = address_ptr_reg; + data_ptr_next = data_ptr_reg; + + cur_address_next = cur_address_reg; + + delay_counter_next = delay_counter_reg; + + m_axis_cmd_address_next = m_axis_cmd_address_reg; + m_axis_cmd_start_next = m_axis_cmd_start_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready); + m_axis_cmd_write_next = m_axis_cmd_write_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready); + m_axis_cmd_stop_next = m_axis_cmd_stop_reg && !(m_axis_cmd.tvalid && m_axis_cmd.tready); + m_axis_cmd_valid_next = m_axis_cmd_valid_reg && !m_axis_cmd.tready; + + m_axis_tx_tdata_next = m_axis_tx_tdata_reg; + m_axis_tx_tvalid_next = m_axis_tx_tvalid_reg && !m_axis_tx.tready; + + start_flag_next = start_flag_reg; + + if (m_axis_cmd.tvalid || m_axis_tx.tvalid) begin + // wait for output registers to clear + state_next = state_reg; + end else if (delay_counter_reg != 0) begin + // delay + delay_counter_next = delay_counter_reg - 1; + state_next = state_reg; + end else begin + case (state_reg) + STATE_IDLE: begin + // wait for start signal + if (!start_flag_reg && start) begin + address_next = '0; + start_flag_next = 1'b1; + state_next = STATE_RUN; + end else begin + state_next = STATE_IDLE; + end + end + STATE_RUN: begin + // process commands + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_tx_tdata_next = init_data_reg[7:0]; + m_axis_tx_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg[8:4] == 5'b00001) begin + // delay + if (SIM_SPEEDUP) begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]); + end else begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]+16); + end + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_RUN; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_RUN; + end + end + STATE_TABLE_1: begin + // find address table start + if (init_data_reg == 9'b000001000) begin + // address table start + address_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end + end + STATE_TABLE_2: begin + // find next address + if (init_data_reg[8:7] == 2'b01) begin + // write address command + // store address and move to data table + cur_address_next = init_data_reg[6:0]; + address_ptr_next = address_reg + 1; + address_next = data_ptr_reg; + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_2; + end + end + STATE_TABLE_3: begin + // process data table with selected address + if (init_data_reg[8] == 1'b1) begin + // write data + m_axis_cmd_write_next = 1'b1; + m_axis_cmd_stop_next = 1'b0; + m_axis_cmd_valid_next = 1'b1; + + m_axis_tx_tdata_next = init_data_reg[7:0]; + m_axis_tx_tvalid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg[8:7] == 2'b01) begin + // write address + m_axis_cmd_address_next = init_data_reg[6:0]; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000000011) begin + // write current address + m_axis_cmd_address_next = cur_address_reg; + m_axis_cmd_start_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg[8:4] == 5'b00001) begin + // delay + if (SIM_SPEEDUP) begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]); + end else begin + delay_counter_next = 32'd1 << (init_data_reg[3:0]+16); + end + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b001000001) begin + // send stop + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + address_next = address_reg + 1; + + state_next = STATE_TABLE_3; + end else if (init_data_reg == 9'b000001001) begin + // data table start + data_ptr_next = address_reg + 1; + address_next = address_reg + 1; + state_next = STATE_TABLE_1; + end else if (init_data_reg == 9'b000001000) begin + // address table start + address_next = address_ptr_reg; + state_next = STATE_TABLE_2; + end else if (init_data_reg == 9'd1) begin + // exit mode + address_next = address_reg + 1; + state_next = STATE_RUN; + end else if (init_data_reg == 9'd0) begin + // stop + m_axis_cmd_start_next = 1'b0; + m_axis_cmd_write_next = 1'b0; + m_axis_cmd_stop_next = 1'b1; + m_axis_cmd_valid_next = 1'b1; + + state_next = STATE_IDLE; + end else begin + // invalid command, skip + address_next = address_reg + 1; + state_next = STATE_TABLE_3; + end + end + default: begin + // invalid state + state_next = STATE_IDLE; + end + endcase + end +end + +always_ff @(posedge clk) begin + state_reg <= state_next; + + // read init_data ROM + init_data_reg <= init_data[address_next]; + + address_reg <= address_next; + address_ptr_reg <= address_ptr_next; + data_ptr_reg <= data_ptr_next; + + cur_address_reg <= cur_address_next; + + delay_counter_reg <= delay_counter_next; + + m_axis_cmd_address_reg <= m_axis_cmd_address_next; + m_axis_cmd_start_reg <= m_axis_cmd_start_next; + m_axis_cmd_write_reg <= m_axis_cmd_write_next; + m_axis_cmd_stop_reg <= m_axis_cmd_stop_next; + m_axis_cmd_valid_reg <= m_axis_cmd_valid_next; + + m_axis_tx_tdata_reg <= m_axis_tx_tdata_next; + m_axis_tx_tvalid_reg <= m_axis_tx_tvalid_next; + + start_flag_reg <= start && start_flag_next; + + busy_reg <= (state_reg != STATE_IDLE); + + if (rst) begin + state_reg <= STATE_IDLE; + + init_data_reg <= '0; + + address_reg <= '0; + address_ptr_reg <= '0; + data_ptr_reg <= '0; + + cur_address_reg <= '0; + + delay_counter_reg <= '0; + + m_axis_cmd_valid_reg <= 1'b0; + + m_axis_tx_tvalid_reg <= 1'b0; + + start_flag_reg <= 1'b0; + + busy_reg <= 1'b0; + end +end + +endmodule + +`resetall \ No newline at end of file diff --git a/src/eth/example/ZCU111/fpga/rtl/fpga.sv b/src/eth/example/ZCU111/fpga/rtl/fpga.sv index de7a078..a032f04 100644 --- a/src/eth/example/ZCU111/fpga/rtl/fpga.sv +++ b/src/eth/example/ZCU111/fpga/rtl/fpga.sv @@ -32,6 +32,10 @@ module fpga # input wire logic clk_125mhz_p, input wire logic clk_125mhz_n, input wire logic reset, + input wire logic fpga_refclk_p, + input wire logic fpga_refclk_n, + input wire logic fpga_sysref_p, + input wire logic fpga_sysref_n, /* * GPIO @@ -44,6 +48,14 @@ module fpga # input wire logic [7:0] sw, output wire logic [7:0] led, + /* + * I2C for board management + */ + inout wire logic i2c0_scl, + inout wire logic i2c0_sda, + inout wire logic i2c1_scl, + inout wire logic i2c1_sda, + /* * UART: 115200 bps, 8N1 */ @@ -61,7 +73,33 @@ module fpga # output wire logic [3:0] sfp_tx_n, input wire logic sfp_mgt_refclk_0_p, input wire logic sfp_mgt_refclk_0_n, - output wire logic [3:0] sfp_tx_disable_b + output wire logic [3:0] sfp_tx_disable_b, + + /* + * RFDC + */ + input wire logic [7:0] adc_vin_p, + input wire logic [7:0] adc_vin_n, + + input wire logic adc_refclk_0_p, + input wire logic adc_refclk_0_n, + input wire logic adc_refclk_1_p, + input wire logic adc_refclk_1_n, + input wire logic adc_refclk_2_p, + input wire logic adc_refclk_2_n, + input wire logic adc_refclk_3_p, + input wire logic adc_refclk_3_n, + + output wire logic [7:0] dac_vout_p, + output wire logic [7:0] dac_vout_n, + + input wire logic dac_refclk_0_p, + input wire logic dac_refclk_0_n, + input wire logic dac_refclk_1_p, + input wire logic dac_refclk_1_n, + + input wire logic rfdc_sysref_p, + input wire logic rfdc_sysref_n ); wire clk_125mhz_ibufg; @@ -78,12 +116,12 @@ wire mmcm_clkfb; IBUFGDS #( .DIFF_TERM("FALSE"), - .IBUF_LOW_PWR("FALSE") + .IBUF_LOW_PWR("FALSE") ) clk_125mhz_ibufg_inst ( .O (clk_125mhz_ibufg), .I (clk_125mhz_p), - .IB (clk_125mhz_n) + .IB (clk_125mhz_n) ); BUFG @@ -185,6 +223,43 @@ sync_reset_125mhz_inst ( .out(rst_125mhz_int) ); +wire fpga_refclk_ibufg; +wire fpga_refclk_int; +wire fpga_sysref_ibufg; +wire fpga_sysref_int; + +IBUFGDS #( + .DIFF_TERM("FALSE"), + .IBUF_LOW_PWR("FALSE") +) +fpga_refclk_ibufg_inst ( + .O (fpga_refclk_ibufg), + .I (fpga_refclk_p), + .IB (fpga_refclk_n) +); + +BUFG +fpga_refclk_bufg_inst ( + .I(fpga_refclk_ibufg), + .O(fpga_refclk_int) +); + +IBUFGDS #( + .DIFF_TERM("FALSE"), + .IBUF_LOW_PWR("FALSE") +) +fpga_sysref_ibufg_inst ( + .O (fpga_sysref_ibufg), + .I (fpga_sysref_p), + .IB (fpga_sysref_n) +); + +BUFG +fpga_sysref_bufg_inst ( + .I(fpga_sysref_ibufg), + .O(fpga_sysref_int) +); + // GPIO wire btnu_int; wire btnl_int; @@ -228,10 +303,629 @@ sync_signal_inst ( .out({uart_rxd_int, uart_rts_int}) ); +wire i2c0_scl_i; +wire i2c0_scl_o; +wire i2c0_sda_i; +wire i2c0_sda_o; + +assign i2c0_scl_i = i2c0_scl; +assign i2c0_scl = i2c0_scl_o ? 1'bz : 1'b0; +assign i2c0_sda_i = i2c0_sda; +assign i2c0_sda = i2c0_sda_o ? 1'bz : 1'b0; + +wire i2c1_scl_i; +wire i2c1_scl_o; +wire i2c1_sda_i; +wire i2c1_sda_o; + +assign i2c1_scl_i = i2c1_scl; +assign i2c1_scl = i2c1_scl_o ? 1'bz : 1'b0; +assign i2c1_sda_i = i2c1_sda; +assign i2c1_sda = i2c1_sda_o ? 1'bz : 1'b0; + +wire i2c1_init_scl_i = i2c1_scl_i; +wire i2c1_init_scl_o; +wire i2c1_init_sda_i = i2c1_sda_i; +wire i2c1_init_sda_o; + +wire i2c1_int_scl_i = i2c1_scl_i; +wire i2c1_int_scl_o; +wire i2c1_int_sda_i = i2c1_sda_i; +wire i2c1_int_sda_o; + +assign i2c1_scl_o = i2c1_init_scl_o & i2c1_int_scl_o; +assign i2c1_sda_o = i2c1_init_sda_o & i2c1_int_sda_o; + +// PLL init +taxi_axis_if #(.DATA_W(12)) pll_i2c_cmd(); +taxi_axis_if #(.DATA_W(8)) pll_i2c_tx(); +taxi_axis_if #(.DATA_W(8)) pll_i2c_rx(); + +assign pll_i2c_rx.tready = 1'b1; + +wire pll_i2c_busy; + +taxi_i2c_master +pll_i2c_master_inst ( + .clk(clk_125mhz_int), + .rst(rst_125mhz_int), + + /* + * Host interface + */ + .s_axis_cmd(pll_i2c_cmd), + .s_axis_tx(pll_i2c_tx), + .m_axis_rx(pll_i2c_rx), + + /* + * I2C interface + */ + .scl_i(i2c1_init_scl_i), + .scl_o(i2c1_init_scl_o), + .sda_i(i2c1_init_sda_i), + .sda_o(i2c1_init_sda_o), + + /* + * Status + */ + .busy(), + .bus_control(), + .bus_active(), + .missed_ack(), + + /* + * Configuration + */ + .prescale(SIM ? 32 : 312), + .stop_on_idle(1) +); + +pll_i2c_init #( + .SIM_SPEEDUP(SIM) +) +pll_i2c_init_inst ( + .clk(clk_125mhz_int), + .rst(rst_125mhz_int), + + /* + * I2C master interface + */ + .m_axis_cmd(pll_i2c_cmd), + .m_axis_tx(pll_i2c_tx), + + /* + * Status + */ + .busy(pll_i2c_busy), + + /* + * Configuration + */ + .start(1'b1) +); + +// RF data converters +localparam ADC_CNT = 8; +localparam ADC_SAMPLE_W = 16; +localparam ADC_SAMPLE_CNT = 4; +localparam ADC_DATA_W = ADC_SAMPLE_W*ADC_SAMPLE_CNT; + +localparam DAC_CNT = ADC_CNT; +localparam DAC_SAMPLE_W = ADC_SAMPLE_W; +localparam DAC_SAMPLE_CNT = ADC_SAMPLE_CNT; +localparam DAC_DATA_W = DAC_SAMPLE_W*DAC_SAMPLE_CNT; + +taxi_axil_if #( + .DATA_W(32), + .ADDR_W(18) +) axil_rfdc(); + +taxi_axis_if #( + .DATA_W(ADC_DATA_W), + .KEEP_EN(1), + .KEEP_W(ADC_SAMPLE_CNT), + .LAST_EN(0), + .USER_EN(0), + .ID_EN(0), + .DEST_EN(0) +) axis_adc[ADC_CNT](); + +// for probing with ILA +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_0 = axis_adc[0].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_1 = axis_adc[1].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_2 = axis_adc[2].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_3 = axis_adc[3].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_4 = axis_adc[4].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_5 = axis_adc[5].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_6 = axis_adc[6].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [ADC_DATA_W-1:0] adc_data_7 = axis_adc[7].tdata; + +taxi_axis_if #( + .DATA_W(DAC_DATA_W), + .KEEP_EN(1), + .KEEP_W(DAC_SAMPLE_CNT), + .LAST_EN(0), + .USER_EN(0), + .ID_EN(0), + .DEST_EN(0) +) axis_dac[DAC_CNT](); + +// for probing with ILA +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_0 = axis_dac[0].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_1 = axis_dac[1].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_2 = axis_dac[2].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_3 = axis_dac[3].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_4 = axis_dac[4].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_5 = axis_dac[5].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_6 = axis_dac[6].tdata; +(* MARK_DEBUG = "TRUE" *) +wire [DAC_DATA_W-1:0] dac_data_7 = axis_dac[7].tdata; + +wire axil_rfdc_clk = clk_125mhz_int; +wire axil_rfdc_rst; + +taxi_sync_reset #( + .N(4) +) +sync_reset_axil_rfdc_inst ( + .clk(axil_rfdc_clk), + .rst(rst_125mhz_int && !pll_i2c_busy), + .out(axil_rfdc_rst) +); + +wire [3:0] adc_clk_out; +wire [3:0] adc_fabric_clk; +wire [3:0] adc_fabric_rst; + +wire axis_adc_clk[8]; +wire axis_adc_rst[8]; + +assign axis_adc_clk[0] = adc_fabric_clk[0]; +assign axis_adc_clk[1] = adc_fabric_clk[0]; +assign axis_adc_clk[2] = adc_fabric_clk[1]; +assign axis_adc_clk[3] = adc_fabric_clk[1]; +assign axis_adc_clk[4] = adc_fabric_clk[2]; +assign axis_adc_clk[5] = adc_fabric_clk[2]; +assign axis_adc_clk[6] = adc_fabric_clk[3]; +assign axis_adc_clk[7] = adc_fabric_clk[3]; +assign axis_adc_rst[0] = adc_fabric_rst[0]; +assign axis_adc_rst[1] = adc_fabric_rst[0]; +assign axis_adc_rst[2] = adc_fabric_rst[1]; +assign axis_adc_rst[3] = adc_fabric_rst[1]; +assign axis_adc_rst[4] = adc_fabric_rst[2]; +assign axis_adc_rst[5] = adc_fabric_rst[2]; +assign axis_adc_rst[6] = adc_fabric_rst[3]; +assign axis_adc_rst[7] = adc_fabric_rst[3]; + +for (genvar n = 0; n < 1; n = n + 1) begin : adc_clk + + wire mmcm_in = adc_clk_out[n]; + wire mmcm_rst = axil_rfdc_rst; + wire mmcm_clkfb; + wire mmcm_locked; + wire mmcm_out; + + wire bufg_out; + wire sync_rst; + + assign adc_fabric_clk[0] = bufg_out; + assign adc_fabric_rst[0] = sync_rst; + assign adc_fabric_clk[1] = bufg_out; + assign adc_fabric_rst[1] = sync_rst; + assign adc_fabric_clk[2] = bufg_out; + assign adc_fabric_rst[2] = sync_rst; + assign adc_fabric_clk[3] = bufg_out; + assign adc_fabric_rst[3] = sync_rst; + + // MMCM instance + MMCME4_BASE #( + // 62.5 MHz input + .CLKIN1_PERIOD(16.0), + .REF_JITTER1(0.010), + // 62.5 MHz input / 1 = 62.5 MHz PFD (range 10 MHz to 500 MHz) + .DIVCLK_DIVIDE(1), + // 62.5 MHz PFD * 20 = 1250 MHz VCO (range 800 MHz to 1600 MHz) + .CLKFBOUT_MULT_F(20), + .CLKFBOUT_PHASE(0), + // 1250 MHz / 5 = 250 MHz, 0 degrees + .CLKOUT0_DIVIDE_F(5), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0), + // Not used + .CLKOUT1_DIVIDE(1), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0), + // Not used + .CLKOUT2_DIVIDE(1), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0), + // Not used + .CLKOUT3_DIVIDE(1), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0), + // Not used + .CLKOUT4_DIVIDE(1), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0), + .CLKOUT4_CASCADE("FALSE"), + // Not used + .CLKOUT5_DIVIDE(1), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0), + // Not used + .CLKOUT6_DIVIDE(1), + .CLKOUT6_DUTY_CYCLE(0.5), + .CLKOUT6_PHASE(0), + + // optimized bandwidth + .BANDWIDTH("OPTIMIZED"), + // don't wait for lock during startup + .STARTUP_WAIT("FALSE") + ) + mmcm_inst ( + // 62.5 MHz input + .CLKIN1(mmcm_in), + // direct clkfb feeback + .CLKFBIN(mmcm_clkfb), + .CLKFBOUT(mmcm_clkfb), + .CLKFBOUTB(), + // 250 MHz, 0 degrees + .CLKOUT0(mmcm_out), + .CLKOUT0B(), + // Not used + .CLKOUT1(), + .CLKOUT1B(), + // Not used + .CLKOUT2(), + .CLKOUT2B(), + // Not used + .CLKOUT3(), + .CLKOUT3B(), + // Not used + .CLKOUT4(), + // Not used + .CLKOUT5(), + // Not used + .CLKOUT6(), + // reset input + .RST(mmcm_rst), + // don't power down + .PWRDWN(1'b0), + // locked output + .LOCKED(mmcm_locked) + ); + + BUFG + bufg_inst ( + .I(mmcm_out), + .O(bufg_out) + ); + + taxi_sync_reset #( + .N(4) + ) + sync_reset_inst ( + .clk(bufg_out), + .rst(!mmcm_locked || mmcm_rst), + .out(sync_rst) + ); + +end + +wire [1:0] dac_clk_out; +wire [1:0] dac_fabric_clk; +wire [1:0] dac_fabric_rst; + +wire axis_dac_clk[8]; +wire axis_dac_rst[8]; + +assign axis_dac_clk[0] = dac_fabric_clk[0]; +assign axis_dac_clk[1] = dac_fabric_clk[0]; +assign axis_dac_clk[2] = dac_fabric_clk[0]; +assign axis_dac_clk[3] = dac_fabric_clk[0]; +assign axis_dac_clk[4] = dac_fabric_clk[1]; +assign axis_dac_clk[5] = dac_fabric_clk[1]; +assign axis_dac_clk[6] = dac_fabric_clk[1]; +assign axis_dac_clk[7] = dac_fabric_clk[1]; +assign axis_dac_rst[0] = dac_fabric_rst[0]; +assign axis_dac_rst[1] = dac_fabric_rst[0]; +assign axis_dac_rst[2] = dac_fabric_rst[0]; +assign axis_dac_rst[3] = dac_fabric_rst[0]; +assign axis_dac_rst[4] = dac_fabric_rst[1]; +assign axis_dac_rst[5] = dac_fabric_rst[1]; +assign axis_dac_rst[6] = dac_fabric_rst[1]; +assign axis_dac_rst[7] = dac_fabric_rst[1]; + +for (genvar n = 0; n < 1; n = n + 1) begin : dac_clk + + wire mmcm_in = dac_clk_out[n]; + wire mmcm_rst = axil_rfdc_rst; + wire mmcm_clkfb; + wire mmcm_locked; + wire mmcm_out; + + wire bufg_out; + wire sync_rst; + + assign dac_fabric_clk[0] = bufg_out; + assign dac_fabric_rst[0] = sync_rst; + assign dac_fabric_clk[1] = bufg_out; + assign dac_fabric_rst[1] = sync_rst; + + // MMCM instance + MMCME4_BASE #( + // 62.5 MHz input + .CLKIN1_PERIOD(16.0), + .REF_JITTER1(0.010), + // 62.5 MHz input / 1 = 62.5 MHz PFD (range 10 MHz to 500 MHz) + .DIVCLK_DIVIDE(1), + // 62.5 MHz PFD * 20 = 1250 MHz VCO (range 800 MHz to 1600 MHz) + .CLKFBOUT_MULT_F(20), + .CLKFBOUT_PHASE(0), + // 1250 MHz / 5 = 250 MHz, 0 degrees + .CLKOUT0_DIVIDE_F(5), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0), + // Not used + .CLKOUT1_DIVIDE(1), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0), + // Not used + .CLKOUT2_DIVIDE(1), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(0), + // Not used + .CLKOUT3_DIVIDE(1), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0), + // Not used + .CLKOUT4_DIVIDE(1), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0), + .CLKOUT4_CASCADE("FALSE"), + // Not used + .CLKOUT5_DIVIDE(1), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(0), + // Not used + .CLKOUT6_DIVIDE(1), + .CLKOUT6_DUTY_CYCLE(0.5), + .CLKOUT6_PHASE(0), + + // optimized bandwidth + .BANDWIDTH("OPTIMIZED"), + // don't wait for lock during startup + .STARTUP_WAIT("FALSE") + ) + mmcm_inst ( + // 62.5 MHz input + .CLKIN1(mmcm_in), + // direct clkfb feeback + .CLKFBIN(mmcm_clkfb), + .CLKFBOUT(mmcm_clkfb), + .CLKFBOUTB(), + // 250 MHz, 0 degrees + .CLKOUT0(mmcm_out), + .CLKOUT0B(), + // Not used + .CLKOUT1(), + .CLKOUT1B(), + // Not used + .CLKOUT2(), + .CLKOUT2B(), + // Not used + .CLKOUT3(), + .CLKOUT3B(), + // Not used + .CLKOUT4(), + // Not used + .CLKOUT5(), + // Not used + .CLKOUT6(), + // reset input + .RST(mmcm_rst), + // don't power down + .PWRDWN(1'b0), + // locked output + .LOCKED(mmcm_locked) + ); + + BUFG + bufg_inst ( + .I(mmcm_out), + .O(bufg_out) + ); + + taxi_sync_reset #( + .N(4) + ) + sync_reset_inst ( + .clk(bufg_out), + .rst(!mmcm_locked || mmcm_rst), + .out(sync_rst) + ); + +end + +usp_rfdc_0 rfdc_inst ( + // Common + .sysref_in_p(rfdc_sysref_p), + .sysref_in_n(rfdc_sysref_n), + + .s_axi_aclk(axil_rfdc_clk), + .s_axi_aresetn(!axil_rfdc_rst), + .s_axi_awaddr(axil_rfdc.awaddr), + .s_axi_awvalid(axil_rfdc.awvalid), + .s_axi_awready(axil_rfdc.awready), + .s_axi_wdata(axil_rfdc.wdata), + .s_axi_wstrb(axil_rfdc.wstrb), + .s_axi_wvalid(axil_rfdc.wvalid), + .s_axi_wready(axil_rfdc.wready), + .s_axi_bresp(axil_rfdc.bresp), + .s_axi_bvalid(axil_rfdc.bvalid), + .s_axi_bready(axil_rfdc.bready), + .s_axi_araddr(axil_rfdc.araddr), + .s_axi_arvalid(axil_rfdc.arvalid), + .s_axi_arready(axil_rfdc.arready), + .s_axi_rdata(axil_rfdc.rdata), + .s_axi_rresp(axil_rfdc.rresp), + .s_axi_rvalid(axil_rfdc.rvalid), + .s_axi_rready(axil_rfdc.rready), + + .irq(), + + // ADC + .adc0_clk_p(adc_refclk_0_p), + .adc0_clk_n(adc_refclk_0_n), + .clk_adc0(adc_clk_out[0]), + + .adc1_clk_p(adc_refclk_1_p), + .adc1_clk_n(adc_refclk_1_n), + .clk_adc1(adc_clk_out[1]), + + .adc2_clk_p(adc_refclk_2_p), + .adc2_clk_n(adc_refclk_2_n), + .clk_adc2(adc_clk_out[2]), + + .adc3_clk_p(adc_refclk_3_p), + .adc3_clk_n(adc_refclk_3_n), + .clk_adc3(adc_clk_out[3]), + + .vin0_01_p(adc_vin_p[0]), + .vin0_01_n(adc_vin_n[0]), + .vin0_23_p(adc_vin_p[1]), + .vin0_23_n(adc_vin_n[1]), + + .vin1_01_p(adc_vin_p[2]), + .vin1_01_n(adc_vin_n[2]), + .vin1_23_p(adc_vin_p[3]), + .vin1_23_n(adc_vin_n[3]), + + .vin2_01_p(adc_vin_p[4]), + .vin2_01_n(adc_vin_n[4]), + .vin2_23_p(adc_vin_p[5]), + .vin2_23_n(adc_vin_n[5]), + + .vin3_01_p(adc_vin_p[6]), + .vin3_01_n(adc_vin_n[6]), + .vin3_23_p(adc_vin_p[7]), + .vin3_23_n(adc_vin_n[7]), + + .m0_axis_aresetn(!adc_fabric_rst[0]), + .m0_axis_aclk(adc_fabric_clk[0]), + .m00_axis_tdata(axis_adc[0].tdata), + .m00_axis_tvalid(axis_adc[0].tvalid), + .m00_axis_tready(axis_adc[0].tready), + .m02_axis_tdata(axis_adc[1].tdata), + .m02_axis_tvalid(axis_adc[1].tvalid), + .m02_axis_tready(axis_adc[1].tready), + + .m1_axis_aresetn(!adc_fabric_rst[1]), + .m1_axis_aclk(adc_fabric_clk[1]), + .m10_axis_tdata(axis_adc[2].tdata), + .m10_axis_tvalid(axis_adc[2].tvalid), + .m10_axis_tready(axis_adc[2].tready), + .m12_axis_tdata(axis_adc[3].tdata), + .m12_axis_tvalid(axis_adc[3].tvalid), + .m12_axis_tready(axis_adc[3].tready), + + .m2_axis_aresetn(!adc_fabric_rst[2]), + .m2_axis_aclk(adc_fabric_clk[2]), + .m20_axis_tdata(axis_adc[4].tdata), + .m20_axis_tvalid(axis_adc[4].tvalid), + .m20_axis_tready(axis_adc[4].tready), + .m22_axis_tdata(axis_adc[5].tdata), + .m22_axis_tvalid(axis_adc[5].tvalid), + .m22_axis_tready(axis_adc[5].tready), + + .m3_axis_aresetn(!adc_fabric_rst[3]), + .m3_axis_aclk(adc_fabric_clk[3]), + .m30_axis_tdata(axis_adc[6].tdata), + .m30_axis_tvalid(axis_adc[6].tvalid), + .m30_axis_tready(axis_adc[6].tready), + .m32_axis_tdata(axis_adc[7].tdata), + .m32_axis_tvalid(axis_adc[7].tvalid), + .m32_axis_tready(axis_adc[7].tready), + + // DAC + .dac0_clk_p(dac_refclk_0_p), + .dac0_clk_n(dac_refclk_0_n), + .clk_dac0(dac_clk_out[0]), + + .dac1_clk_p(dac_refclk_1_p), + .dac1_clk_n(dac_refclk_1_n), + .clk_dac1(dac_clk_out[1]), + + .vout00_p(dac_vout_p[0]), + .vout00_n(dac_vout_n[0]), + .vout01_p(dac_vout_p[1]), + .vout01_n(dac_vout_n[1]), + .vout02_p(dac_vout_p[2]), + .vout02_n(dac_vout_n[2]), + .vout03_p(dac_vout_p[3]), + .vout03_n(dac_vout_n[3]), + + .vout10_p(dac_vout_p[4]), + .vout10_n(dac_vout_n[4]), + .vout11_p(dac_vout_p[5]), + .vout11_n(dac_vout_n[5]), + .vout12_p(dac_vout_p[6]), + .vout12_n(dac_vout_n[6]), + .vout13_p(dac_vout_p[7]), + .vout13_n(dac_vout_n[7]), + + .s0_axis_aresetn(!dac_fabric_rst[0]), + .s0_axis_aclk(dac_fabric_clk[0]), + .s00_axis_tdata(axis_dac[0].tdata), + .s00_axis_tvalid(axis_dac[0].tvalid), + .s00_axis_tready(axis_dac[0].tready), + .s01_axis_tdata(axis_dac[1].tdata), + .s01_axis_tvalid(axis_dac[1].tvalid), + .s01_axis_tready(axis_dac[1].tready), + .s02_axis_tdata(axis_dac[2].tdata), + .s02_axis_tvalid(axis_dac[2].tvalid), + .s02_axis_tready(axis_dac[2].tready), + .s03_axis_tdata(axis_dac[3].tdata), + .s03_axis_tvalid(axis_dac[3].tvalid), + .s03_axis_tready(axis_dac[3].tready), + + .s1_axis_aresetn(!dac_fabric_rst[1]), + .s1_axis_aclk(dac_fabric_clk[1]), + .s10_axis_tdata(axis_dac[4].tdata), + .s10_axis_tvalid(axis_dac[4].tvalid), + .s10_axis_tready(axis_dac[4].tready), + .s11_axis_tdata(axis_dac[5].tdata), + .s11_axis_tvalid(axis_dac[5].tvalid), + .s11_axis_tready(axis_dac[5].tready), + .s12_axis_tdata(axis_dac[6].tdata), + .s12_axis_tvalid(axis_dac[6].tvalid), + .s12_axis_tready(axis_dac[6].tready), + .s13_axis_tdata(axis_dac[7].tdata), + .s13_axis_tvalid(axis_dac[7].tvalid), + .s13_axis_tready(axis_dac[7].tready) +); + fpga_core #( .SIM(SIM), .VENDOR(VENDOR), - .FAMILY(FAMILY) + .FAMILY(FAMILY), + .ADC_CNT(ADC_CNT), + .DAC_CNT(DAC_CNT) ) core_inst ( /* @@ -240,6 +934,8 @@ core_inst ( */ .clk_125mhz(clk_125mhz_int), .rst_125mhz(rst_125mhz_int), + .fpga_refclk(fpga_refclk_int), + .fpga_sysref(fpga_sysref_int), /* * GPIO @@ -252,6 +948,18 @@ core_inst ( .sw(sw_int), .led(led), + /* + * I2C for board management + */ + .i2c0_scl_i(i2c0_scl_i), + .i2c0_scl_o(i2c0_scl_o), + .i2c0_sda_i(i2c0_sda_i), + .i2c0_sda_o(i2c0_sda_o), + .i2c1_scl_i(i2c1_int_scl_i), + .i2c1_scl_o(i2c1_int_scl_o), + .i2c1_sda_i(i2c1_int_sda_i), + .i2c1_sda_o(i2c1_int_sda_o), + /* * UART: 115200 bps, 8N1 */ @@ -270,7 +978,23 @@ core_inst ( .sfp_mgt_refclk_0_p(sfp_mgt_refclk_0_p), .sfp_mgt_refclk_0_n(sfp_mgt_refclk_0_n), - .sfp_tx_disable_b(sfp_tx_disable_b) + .sfp_tx_disable_b(sfp_tx_disable_b), + + /* + * RFDC + */ + .axil_rfdc_clk(axil_rfdc_clk), + .axil_rfdc_rst(axil_rfdc_rst), + .m_axil_rfdc_wr(axil_rfdc), + .m_axil_rfdc_rd(axil_rfdc), + + .axis_adc_clk(axis_adc_clk), + .axis_adc_rst(axis_adc_rst), + .s_axis_adc(axis_adc), + + .axis_dac_clk(axis_dac_clk), + .axis_dac_rst(axis_dac_rst), + .m_axis_dac(axis_dac) ); endmodule diff --git a/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv b/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv index 96584ac..842b547 100644 --- a/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv +++ b/src/eth/example/ZCU111/fpga/rtl/fpga_core.sv @@ -22,7 +22,11 @@ module fpga_core # // vendor ("GENERIC", "XILINX", "ALTERA") parameter string VENDOR = "XILINX", // device family - parameter string FAMILY = "zynquplusRFSOC" + parameter string FAMILY = "zynquplusRFSOC", + // number of RFDC ADC channels + parameter ADC_CNT = 8, + // number of RFDC DAC channels + parameter DAC_CNT = ADC_CNT ) ( /* @@ -31,6 +35,8 @@ module fpga_core # */ input wire logic clk_125mhz, input wire logic rst_125mhz, + input wire logic fpga_refclk, + input wire logic fpga_sysref, /* * GPIO @@ -43,6 +49,18 @@ module fpga_core # input wire logic [7:0] sw, output wire logic [7:0] led, + /* + * I2C for board management + */ + input wire logic i2c0_scl_i, + output wire logic i2c0_scl_o, + input wire logic i2c0_sda_i, + output wire logic i2c0_sda_o, + input wire logic i2c1_scl_i, + output wire logic i2c1_scl_o, + input wire logic i2c1_sda_i, + output wire logic i2c1_sda_o, + /* * UART: 115200 bps, 8N1 */ @@ -61,7 +79,23 @@ module fpga_core # input wire logic sfp_mgt_refclk_0_p, input wire logic sfp_mgt_refclk_0_n, - output wire logic [3:0] sfp_tx_disable_b + output wire logic [3:0] sfp_tx_disable_b, + + /* + * RFDC + */ + input wire logic axil_rfdc_clk, + input wire logic axil_rfdc_rst, + taxi_axil_if.wr_mst m_axil_rfdc_wr, + taxi_axil_if.rd_mst m_axil_rfdc_rd, + + input wire logic axis_adc_clk[ADC_CNT], + input wire logic axis_adc_rst[ADC_CNT], + taxi_axis_if.snk s_axis_adc[ADC_CNT], + + input wire logic axis_dac_clk[DAC_CNT], + input wire logic axis_dac_rst[DAC_CNT], + taxi_axis_if.src m_axis_dac[DAC_CNT] ); assign led = sw; @@ -97,7 +131,7 @@ xfcp_if_uart_inst ( .prescale(16'(125000000/3000000)) ); -taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_sw_ds[1](), xfcp_sw_us[1](); +taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_sw_ds[4](), xfcp_sw_us[4](); taxi_xfcp_switch #( .XFCP_ID_STR("ZCU111"), @@ -170,6 +204,78 @@ stat_mux_inst ( .m_axis(axis_stat) ); +// I2C +taxi_xfcp_mod_i2c_master #( + .XFCP_EXT_ID_STR("I2C0"), + .DEFAULT_PRESCALE(16'(125000000/200000/4)) +) +xfcp_mod_i2c0_inst ( + .clk(clk_125mhz), + .rst(rst_125mhz), + + /* + * XFCP upstream port + */ + .xfcp_usp_ds(xfcp_sw_ds[1]), + .xfcp_usp_us(xfcp_sw_us[1]), + + /* + * I2C interface + */ + .i2c_scl_i(i2c0_scl_i), + .i2c_scl_o(i2c0_scl_o), + .i2c_sda_i(i2c0_sda_i), + .i2c_sda_o(i2c0_sda_o) +); + +taxi_xfcp_mod_i2c_master #( + .XFCP_EXT_ID_STR("I2C1"), + .DEFAULT_PRESCALE(16'(125000000/200000/4)) +) +xfcp_mod_i2c1_inst ( + .clk(clk_125mhz), + .rst(rst_125mhz), + + /* + * XFCP upstream port + */ + .xfcp_usp_ds(xfcp_sw_ds[2]), + .xfcp_usp_us(xfcp_sw_us[2]), + + /* + * I2C interface + */ + .i2c_scl_i(i2c1_scl_i), + .i2c_scl_o(i2c1_scl_o), + .i2c_sda_i(i2c1_sda_i), + .i2c_sda_o(i2c1_sda_o) +); + +// RFDC control +taxi_xfcp_mod_axil #( + // .XFCP_ID_TYPE(16'h8080), + .XFCP_ID_STR("RFDC"), + // .XFCP_EXT_ID(XFCP_EXT_ID), + // .XFCP_EXT_ID_STR(XFCP_EXT_ID_STR), + .COUNT_SIZE(16) +) +xfcp_mod_axil_inst ( + .clk(clk_125mhz), + .rst(rst_125mhz), + + /* + * XFCP upstream port + */ + .xfcp_usp_ds(xfcp_sw_ds[3]), + .xfcp_usp_us(xfcp_sw_us[3]), + + /* + * AXI lite master interface + */ + .m_axil_wr(m_axil_rfdc_wr), + .m_axil_rd(m_axil_rfdc_rd) +); + // SFP+ assign sfp_tx_disable_b = '1; @@ -504,6 +610,53 @@ for (genvar n = 0; n < 4; n = n + 1) begin : sfp_ch end +for (genvar n = 0; n < ADC_CNT; n = n + 1) begin : rfdc_lpbk + + taxi_axis_async_fifo #( + .DEPTH(256), + .RAM_PIPELINE(2), + .FRAME_FIFO(0) + ) + ch_fifo ( + /* + * AXI4-Stream input (sink) + */ + .s_clk(axis_adc_clk[n]), + .s_rst(axis_adc_rst[n]), + .s_axis(s_axis_adc[n]), + + /* + * AXI4-Stream output (source) + */ + .m_clk(axis_dac_clk[n]), + .m_rst(axis_dac_rst[n]), + .m_axis(m_axis_dac[n]), + + /* + * Pause + */ + .s_pause_req(1'b0), + .s_pause_ack(), + .m_pause_req(1'b0), + .m_pause_ack(), + + /* + * Status + */ + .s_status_depth(), + .s_status_depth_commit(), + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_depth(), + .m_status_depth_commit(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() + ); + +end + endmodule `resetall diff --git a/src/eth/example/ZCU111/fpga/tb/fpga_core/Makefile b/src/eth/example/ZCU111/fpga/tb/fpga_core/Makefile index 5ae5899..a0f9c33 100644 --- a/src/eth/example/ZCU111/fpga/tb/fpga_core/Makefile +++ b/src/eth/example/ZCU111/fpga/tb/fpga_core/Makefile @@ -19,14 +19,16 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src DUT = fpga_core COCOTB_TEST_MODULES = test_$(DUT) -COCOTB_TOPLEVEL = $(DUT) +COCOTB_TOPLEVEL = test_$(DUT) MODULE = $(COCOTB_TEST_MODULES) TOPLEVEL = $(COCOTB_TOPLEVEL) +VERILOG_SOURCES += $(COCOTB_TOPLEVEL).sv VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_25g_us.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_if_uart.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f +VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_i2c_master.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/axis/rtl/taxi_axis_async_fifo.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv diff --git a/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py index bf602da..ef176b6 100644 --- a/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.py @@ -48,7 +48,7 @@ class TB: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start()) - for ch in dut.sfp_mac_inst.ch: + for ch in dut.uut.sfp_mac_inst.ch: gt_inst = ch.ch_inst.gt.gt_inst if ch.ch_inst.CFG_LOW_LATENCY.value: @@ -198,14 +198,16 @@ def process_f_files(files): def test_fpga_core(request): dut = "fpga_core" module = os.path.splitext(os.path.basename(__file__))[0] - toplevel = dut + toplevel = module verilog_sources = [ + os.path.join(tests_dir, f"{toplevel}.sv"), os.path.join(rtl_dir, f"{dut}.sv"), os.path.join(taxi_src_dir, "eth", "rtl", "us", "taxi_eth_mac_25g_us.f"), os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_if_uart.f"), os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_switch.sv"), os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_stats.f"), + os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_i2c_master.f"), os.path.join(taxi_src_dir, "axis", "rtl", "taxi_axis_async_fifo.f"), os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_reset.sv"), os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_signal.sv"), diff --git a/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.sv b/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.sv new file mode 100644 index 0000000..9682bd0 --- /dev/null +++ b/src/eth/example/ZCU111/fpga/tb/fpga_core/test_fpga_core.sv @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: MIT +/* + +Copyright (c) 2025 FPGA Ninja, LLC + +Authors: +- Alex Forencich + +*/ + +`resetall +`timescale 1ns / 1ps +`default_nettype none + +/* + * FPGA core logic testbench + */ +module test_fpga_core # +( + /* verilator lint_off WIDTHTRUNC */ + parameter logic SIM = 1'b1, + parameter string VENDOR = "XILINX", + parameter string FAMILY = "zynquplusRFSOC", + parameter ADC_CNT = 8, + parameter ADC_SAMPLE_W = 16, + parameter ADC_SAMPLE_CNT = 4, + parameter DAC_CNT = ADC_CNT, + parameter DAC_SAMPLE_W = ADC_SAMPLE_W, + parameter DAC_SAMPLE_CNT = ADC_SAMPLE_CNT + /* verilator lint_on WIDTHTRUNC */ +) +(); + +localparam ADC_DATA_W = ADC_SAMPLE_W*ADC_SAMPLE_CNT; +localparam DAC_DATA_W = DAC_SAMPLE_W*DAC_SAMPLE_CNT; + +logic clk_125mhz; +logic rst_125mhz; +logic fpga_refclk; +logic fpga_sysref; + +logic btnu; +logic btnl; +logic btnd; +logic btnr; +logic btnc; +logic [7:0] sw; +logic [7:0] led; + +logic i2c0_scl_i; +logic i2c0_scl_o; +logic i2c0_sda_i; +logic i2c0_sda_o; +logic i2c1_scl_i; +logic i2c1_scl_o; +logic i2c1_sda_i; +logic i2c1_sda_o; + +logic uart_rxd; +logic uart_txd; +logic uart_rts; +logic uart_cts; + +logic [3:0] sfp_rx_p; +logic [3:0] sfp_rx_n; +logic [3:0] sfp_tx_p; +logic [3:0] sfp_tx_n; +logic sfp_mgt_refclk_0_p; +logic sfp_mgt_refclk_0_n; + +logic [3:0] sfp_tx_disable_b; + +logic axil_rfdc_clk; +logic axil_rfdc_rst; + +taxi_axil_if #( + .DATA_W(32), + .ADDR_W(18) +) m_axil_rfdc(); + +logic axis_adc_clk[ADC_CNT]; +logic axis_adc_rst[ADC_CNT]; + +taxi_axis_if #( + .DATA_W(ADC_DATA_W), + .KEEP_EN(1), + .KEEP_W(ADC_SAMPLE_CNT), + .LAST_EN(0), + .USER_EN(0), + .ID_EN(0), + .DEST_EN(0) +) s_axis_adc[ADC_CNT](); + +logic axis_dac_clk[DAC_CNT]; +logic axis_dac_rst[DAC_CNT]; + +taxi_axis_if #( + .DATA_W(DAC_DATA_W), + .KEEP_EN(1), + .KEEP_W(DAC_SAMPLE_CNT), + .LAST_EN(0), + .USER_EN(0), + .ID_EN(0), + .DEST_EN(0) +) m_axis_dac[DAC_CNT](); + +fpga_core #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .ADC_CNT(ADC_CNT), + .DAC_CNT(DAC_CNT) +) +uut ( + /* + * Clock: 125MHz + * Synchronous reset + */ + .clk_125mhz(clk_125mhz), + .rst_125mhz(rst_125mhz), + .fpga_refclk(fpga_refclk), + .fpga_sysref(fpga_sysref), + + /* + * GPIO + */ + .btnu(btnu), + .btnl(btnl), + .btnd(btnd), + .btnr(btnr), + .btnc(btnc), + .sw(sw), + .led(led), + + /* + * I2C for board management + */ + .i2c0_scl_i(i2c0_scl_i), + .i2c0_scl_o(i2c0_scl_o), + .i2c0_sda_i(i2c0_sda_i), + .i2c0_sda_o(i2c0_sda_o), + .i2c1_scl_i(i2c1_scl_i), + .i2c1_scl_o(i2c1_scl_o), + .i2c1_sda_i(i2c1_sda_i), + .i2c1_sda_o(i2c1_sda_o), + + /* + * UART: 115200 bps, 8N1 + */ + .uart_rxd(uart_rxd), + .uart_txd(uart_txd), + .uart_rts(uart_rts), + .uart_cts(uart_cts), + + /* + * Ethernet: SFP+ + */ + .sfp_rx_p(sfp_rx_p), + .sfp_rx_n(sfp_rx_n), + .sfp_tx_p(sfp_tx_p), + .sfp_tx_n(sfp_tx_n), + .sfp_mgt_refclk_0_p(sfp_mgt_refclk_0_p), + .sfp_mgt_refclk_0_n(sfp_mgt_refclk_0_n), + + .sfp_tx_disable_b(sfp_tx_disable_b), + + /* + * RFDC + */ + .axil_rfdc_clk(axil_rfdc_clk), + .axil_rfdc_rst(axil_rfdc_rst), + .m_axil_rfdc_wr(m_axil_rfdc), + .m_axil_rfdc_rd(m_axil_rfdc), + + .axis_adc_clk(axis_adc_clk), + .axis_adc_rst(axis_adc_rst), + .s_axis_adc(s_axis_adc), + + .axis_dac_clk(axis_dac_clk), + .axis_dac_rst(axis_dac_rst), + .m_axis_dac(m_axis_dac) +); + +endmodule + +`resetall