eth: Add RFDC to ZCU111 example design

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2025-08-24 11:26:14 -07:00
parent 4c43b68f94
commit 07ae2ba989
14 changed files with 3263 additions and 22 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -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()

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"),

View File

@@ -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