|
| 1 | +############################################################################### |
| 2 | +## Copyright (C) 2025 Analog Devices, Inc. All rights reserved. |
| 3 | +### SPDX short identifier: ADIBSD |
| 4 | +############################################################################### |
| 5 | + |
| 6 | +source ../../../projects/scripts/adi_board.tcl |
| 7 | + |
| 8 | +# Parameter description: |
| 9 | +# ip_name : The name of the created ip |
| 10 | +# jesd_mode : Used physical layer encoder mode |
| 11 | +# rx_no_lanes : Number of RX lanes |
| 12 | +# tx_no_lanes : Number of TX lanes |
| 13 | +# ref_clock : Frequency of reference clock in MHz used in 64B66B mode (LANE_RATE/66) or 8B10B mode (LANE_RATE/40) |
| 14 | +# rx_lane_rate : Line rate of the Rx link ( e.g. MxFE to FPGA ) in GHz |
| 15 | +# tx_lane_rate : Line rate of the Tx link ( e.g. FPGA to MxFE ) in GHz |
| 16 | +# transceiver : Type of transceiver to use (GTY or GTYP) |
| 17 | +# direction : Direction of the transceivers |
| 18 | +# RXTX : Duplex mode |
| 19 | +# RX : Rx link only |
| 20 | +# TX : Tx link only |
| 21 | +proc create_xcvr_subsystem { |
| 22 | + {ip_name xcvr} |
| 23 | + {jesd_mode 64B66B} |
| 24 | + {rx_no_lanes 4} |
| 25 | + {tx_no_lanes 4} |
| 26 | + {rx_lane_rate 24.75} |
| 27 | + {tx_lane_rate 24.75} |
| 28 | + {ref_clock 375} |
| 29 | + {transceiver GTY} |
| 30 | + {direction RX} |
| 31 | +} { |
| 32 | + set clk_divider [expr {$jesd_mode == "64B66B" ? 66 : 40}] |
| 33 | + set datapath_width [expr {$jesd_mode == "64B66B" ? 64 : 32}] |
| 34 | + set internal_datapath_width [expr {$jesd_mode == "64B66B" ? 64 : 40}] |
| 35 | + set data_encoding [expr {$jesd_mode == "64B66B" ? "64B66B_ASYNC" : "8B10B"}] |
| 36 | + set comma_mask [expr {$jesd_mode == "64B66B" ? "0000000000" : "1111111111"}] |
| 37 | + set comma_p_enable [expr {$jesd_mode == "64B66B" ? false : false}] |
| 38 | + set comma_m_enable [expr {$jesd_mode == "64B66B" ? false : false}] |
| 39 | + set rx_progdiv_clock [format %.3f [expr $rx_lane_rate * 1000.0 / ${clk_divider}]] |
| 40 | + set tx_progdiv_clock [format %.3f [expr $tx_lane_rate * 1000.0 / ${clk_divider}]] |
| 41 | + |
| 42 | + if {$direction == "RXTX"} { |
| 43 | + set no_lanes [expr max($rx_no_lanes, $tx_no_lanes)] |
| 44 | + } elseif {$direction == "RX"} { |
| 45 | + set no_lanes $rx_no_lanes |
| 46 | + } else { |
| 47 | + set no_lanes $tx_no_lanes |
| 48 | + } |
| 49 | + set num_quads [expr int(ceil(1.0 * $no_lanes / 4))] |
| 50 | + |
| 51 | + ad_ip_instance gtwiz_versal ${ip_name} |
| 52 | + |
| 53 | + set xcvr_param [dict create] |
| 54 | + |
| 55 | + # RX parameters |
| 56 | + dict set xcvr_param RX_LINE_RATE ${rx_lane_rate} |
| 57 | + dict set xcvr_param RX_DATA_DECODING ${data_encoding} |
| 58 | + dict set xcvr_param RX_REFCLK_FREQUENCY ${ref_clock} |
| 59 | + dict set xcvr_param RX_USER_DATA_WIDTH ${datapath_width} |
| 60 | + dict set xcvr_param RX_INT_DATA_WIDTH ${internal_datapath_width} |
| 61 | + dict set xcvr_param RX_OUTCLK_SOURCE {RXPROGDIVCLK} |
| 62 | + dict set xcvr_param RXRECCLK_FREQ_VAL ${rx_progdiv_clock} |
| 63 | + dict set xcvr_param RXPROGDIV_FREQ_VAL ${rx_progdiv_clock} |
| 64 | + if {$jesd_mode == "8B10B"} { |
| 65 | + dict set xcvr_param RX_COMMA_P_ENABLE ${comma_p_enable} |
| 66 | + dict set xcvr_param RX_COMMA_M_ENABLE ${comma_m_enable} |
| 67 | + dict set xcvr_param RX_COMMA_SHOW_REALIGN_ENABLE {false} |
| 68 | + dict set xcvr_param RX_SLIDE_MODE {PCS} |
| 69 | + } |
| 70 | + |
| 71 | + # Tx parameters |
| 72 | + dict set xcvr_param TX_LINE_RATE ${tx_lane_rate} |
| 73 | + dict set xcvr_param TX_DATA_ENCODING ${data_encoding} |
| 74 | + dict set xcvr_param TX_REFCLK_FREQUENCY ${ref_clock} |
| 75 | + dict set xcvr_param TX_USER_DATA_WIDTH ${datapath_width} |
| 76 | + dict set xcvr_param TX_INT_DATA_WIDTH ${internal_datapath_width} |
| 77 | + dict set xcvr_param TXPROGDIV_FREQ_VAL ${tx_progdiv_clock} |
| 78 | + dict set xcvr_param TX_OUTCLK_SOURCE {TXPROGDIVCLK} |
| 79 | + |
| 80 | + |
| 81 | + set phy_params [dict create] |
| 82 | + dict set phy_params CONFIG.ENABLE_REG_INTERFACE {true} |
| 83 | + dict set phy_params CONFIG.REG_CONF_INTF {AXI_LITE} |
| 84 | + dict set phy_params CONFIG.NO_OF_QUADS ${num_quads} |
| 85 | + dict set phy_params CONFIG.NO_OF_INTERFACE {1} |
| 86 | + dict set phy_params CONFIG.LOCATE_BUFG {CORE} |
| 87 | + dict set phy_params CONFIG.INTF0_PRESET ${transceiver}-JESD204_${jesd_mode} |
| 88 | + dict set phy_params CONFIG.INTF0_GT_SETTINGS(LR0_SETTINGS) ${xcvr_param} |
| 89 | + if {$direction != "RXTX"} { |
| 90 | + dict set phy_params CONFIG.INTF0_GT_DIRECTION SIMPLEX_${direction} |
| 91 | + dict set phy_params CONFIG.INTF0_NO_OF_LANES ${no_lanes} |
| 92 | + } else { |
| 93 | + # When RXTX is selected, create two interfaces |
| 94 | + # Interface 0 for RX |
| 95 | + # Interface 1 for TX |
| 96 | + # This is mandatory if we want to have different number of lanes for RX and TX |
| 97 | + dict set phy_params CONFIG.NO_OF_INTERFACE {2} |
| 98 | + dict set phy_params CONFIG.INTF0_GT_DIRECTION {SIMPLEX_RX} |
| 99 | + dict set phy_params CONFIG.INTF1_GT_DIRECTION {SIMPLEX_TX} |
| 100 | + dict set phy_params CONFIG.INTF0_NO_OF_LANES $rx_no_lanes |
| 101 | + dict set phy_params CONFIG.INTF1_NO_OF_LANES $tx_no_lanes |
| 102 | + dict set phy_params CONFIG.INTF1_PRESET ${transceiver}-JESD204_${jesd_mode} |
| 103 | + dict set phy_params CONFIG.INTF1_GT_SETTINGS(LR0_SETTINGS) ${xcvr_param} |
| 104 | + } |
| 105 | + |
| 106 | + if {$direction != "RXTX"} { |
| 107 | + # Simplex RX or Simplex TX |
| 108 | + # One single interface (Interface 0) |
| 109 | + dict set phy_params "CONFIG.QUAD0_${direction}0_OUTCLK_EN" {true} |
| 110 | + dict set phy_params "CONFIG.QUAD0_PROT0_${direction}MSTCLK" ${direction}0 |
| 111 | + for {set i 0} {$i < [expr 4 * $num_quads]} {incr i} { |
| 112 | + set quad_idx [expr $i / 4] |
| 113 | + set lane_idx [expr $i % 4] |
| 114 | + dict set phy_params "CONFIG.QUAD${quad_idx}_PROT0_${direction}${lane_idx}_EN" [expr $i < $no_lanes] |
| 115 | + } |
| 116 | + for {set i 0} {$i < $num_quads} {incr i} { |
| 117 | + dict set phy_params "CONFIG.QUAD${i}_PROT0_LANES" [expr min(4, max(0, $no_lanes - 4 * $i))] |
| 118 | + } |
| 119 | + } else { |
| 120 | + # Interface 0 = RX |
| 121 | + # Interface 1 = TX |
| 122 | + |
| 123 | + dict set phy_params "CONFIG.QUAD0_RX0_OUTCLK_EN" {true} |
| 124 | + dict set phy_params "CONFIG.QUAD0_TX0_OUTCLK_EN" {true} |
| 125 | + dict set phy_params "CONFIG.QUAD0_PROT0_RXMSTCLK" {RX0} |
| 126 | + # Map RX lanes |
| 127 | + for {set i 0} {$i < $num_quads} {incr i} { |
| 128 | + set lanes [expr min(4, max(0, $rx_no_lanes - 4 * $i))] |
| 129 | + if {$lanes != 0} { |
| 130 | + dict set phy_params "CONFIG.QUAD${i}_PROT0_LANES" ${lanes} |
| 131 | + dict set phy_params "CONFIG.QUAD${i}_NO_PROT" {1} |
| 132 | + } |
| 133 | + } |
| 134 | + for {set i 0} {$i < [expr 4 * $num_quads]} {incr i} { |
| 135 | + set quad_idx [expr $i / 4] |
| 136 | + set lane_idx [expr $i % 4] |
| 137 | + dict set phy_params "CONFIG.QUAD${quad_idx}_PROT0_RX${lane_idx}_EN" [expr $i < $rx_no_lanes] |
| 138 | + } |
| 139 | + |
| 140 | + # Map TX lanes |
| 141 | + dict set phy_params "CONFIG.QUAD0_PROT1_TXMSTCLK" {TX0} |
| 142 | + for {set i 0} {$i < $num_quads} {incr i} { |
| 143 | + set lanes [expr min(4, max(0, $tx_no_lanes - 4 * $i))] |
| 144 | + if {$lanes != 0} { |
| 145 | + if {[dict exists $phy_params "CONFIG.QUAD${i}_PROT0_LANES"]} { |
| 146 | + # Both RX and TX lanes in the same quad |
| 147 | + dict set phy_params "CONFIG.QUAD${i}_NO_PROT" {2} |
| 148 | + dict set phy_params "CONFIG.QUAD${i}_PROT1_LANES" ${lanes} |
| 149 | + } else { |
| 150 | + # Only TX lanes in this quad |
| 151 | + dict set phy_params "CONFIG.QUAD${i}_NO_PROT" {1} |
| 152 | + dict set phy_params "CONFIG.QUAD${i}_PROT0" {INTF1} |
| 153 | + dict set phy_params "CONFIG.QUAD${i}_PROT0_LANES" ${lanes} |
| 154 | + } |
| 155 | + } |
| 156 | + } |
| 157 | + for {set i 0} {$i < [expr 4 * $num_quads]} {incr i} { |
| 158 | + set quad_idx [expr $i / 4] |
| 159 | + set lane_idx [expr $i % 4] |
| 160 | + set prot_idx [expr {[dict get $phy_params "CONFIG.QUAD${quad_idx}_NO_PROT"] - 1}] |
| 161 | + dict set phy_params "CONFIG.QUAD${quad_idx}_PROT${prot_idx}_TX${lane_idx}_EN" [expr $i < $tx_no_lanes] |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + # dict for {k v} $phy_params {puts "$k : $v"} |
| 166 | + set_property -dict $phy_params [get_bd_cells ${ip_name}] |
| 167 | +} |
| 168 | + |
| 169 | +# Parameter description: |
| 170 | +# ip_name : The name of the created ip |
| 171 | +# jesd_mode : Used physical layer encoder mode |
| 172 | +# rx_no_lanes : Number of RX lanes |
| 173 | +# tx_no_lanes : Number of TX lanes |
| 174 | +# ref_clock : Frequency of reference clock in MHz used in 64B66B mode (LANE_RATE/66) or 8B10B mode (LANE_RATE/40) |
| 175 | +# rx_lane_rate : Line rate of the Rx link ( e.g. MxFE to FPGA ) in GHz |
| 176 | +# tx_lane_rate : Line rate of the Tx link ( e.g. FPGA to MxFE ) in GHz |
| 177 | +# transceiver : Type of transceiver to use (GTY or GTYP) |
| 178 | +# intf_cfg : Direction of the transceivers |
| 179 | +# RXTX : Duplex mode |
| 180 | +# RX : Rx link only |
| 181 | +# TX : Tx link only |
| 182 | +proc create_versal_jesd_xcvr_subsystem { |
| 183 | + {ip_name versal_phy} |
| 184 | + {jesd_mode 64B66B} |
| 185 | + {rx_no_lanes 4} |
| 186 | + {tx_no_lanes 4} |
| 187 | + {rx_lane_rate 24.75} |
| 188 | + {tx_lane_rate 24.75} |
| 189 | + {ref_clock 375} |
| 190 | + {transceiver GTY} |
| 191 | + {intf_cfg RXTX} |
| 192 | +} { |
| 193 | + set rx_quads [expr int(ceil(1.0 * $rx_no_lanes / 4))] |
| 194 | + set tx_quads [expr int(ceil(1.0 * $tx_no_lanes / 4))] |
| 195 | + set num_quads [expr max($rx_quads, $tx_quads)] |
| 196 | + set link_mode [expr {$jesd_mode == "64B66B" ? 2 : 1}] |
| 197 | + |
| 198 | + if {$intf_cfg == "RXTX"} { |
| 199 | + set rx_intf 0 |
| 200 | + set tx_intf 1 |
| 201 | + } else { |
| 202 | + set rx_intf 0 |
| 203 | + set tx_intf 0 |
| 204 | + } |
| 205 | + |
| 206 | + create_bd_cell -type hier ${ip_name} |
| 207 | + |
| 208 | + # Common interface |
| 209 | + create_bd_pin -dir I ${ip_name}/GT_REFCLK -type clk |
| 210 | + create_bd_pin -dir I ${ip_name}/s_axi_clk |
| 211 | + create_bd_pin -dir I ${ip_name}/s_axi_resetn |
| 212 | + if {$intf_cfg != "TX"} { |
| 213 | + create_bd_pin -dir O ${ip_name}/rxusrclk_out -type clk |
| 214 | + create_bd_pin -dir I ${ip_name}/en_char_align |
| 215 | + } |
| 216 | + if {$intf_cfg != "RX"} { |
| 217 | + create_bd_pin -dir O ${ip_name}/txusrclk_out -type clk |
| 218 | + } |
| 219 | + |
| 220 | + create_xcvr_subsystem ${ip_name}/xcvr $jesd_mode $rx_no_lanes $tx_no_lanes $rx_lane_rate $tx_lane_rate $ref_clock $transceiver $intf_cfg |
| 221 | + |
| 222 | + # Common xcvr connection |
| 223 | + for {set j 0} {$j < $num_quads} {incr j} { |
| 224 | + ad_connect ${ip_name}/GT_REFCLK ${ip_name}/xcvr/QUAD${j}_GTREFCLK0 |
| 225 | + } |
| 226 | + |
| 227 | + if {$intf_cfg != "TX"} { |
| 228 | + ad_ip_instance bufg_gt ${ip_name}/bufg_gt_rx |
| 229 | + ad_connect ${ip_name}/xcvr/INTF${rx_intf}_rx_clr_out ${ip_name}/bufg_gt_rx/gt_bufgtclr |
| 230 | + ad_connect ${ip_name}/xcvr/QUAD0_RX0_outclk ${ip_name}/bufg_gt_rx/outclk |
| 231 | + ad_connect ${ip_name}/bufg_gt_rx/usrclk ${ip_name}/rxusrclk_out |
| 232 | + |
| 233 | + for {set j 0} {$j < $rx_quads} {incr j} { |
| 234 | + create_bd_pin -dir I -from 3 -to 0 ${ip_name}/rx_${j}_p |
| 235 | + create_bd_pin -dir I -from 3 -to 0 ${ip_name}/rx_${j}_n |
| 236 | + ad_connect ${ip_name}/xcvr/QUAD${j}_rxp ${ip_name}/rx_${j}_p |
| 237 | + ad_connect ${ip_name}/xcvr/QUAD${j}_rxn ${ip_name}/rx_${j}_n |
| 238 | + } |
| 239 | + |
| 240 | + for {set j 0} {$j < $rx_no_lanes} {incr j} { |
| 241 | + ad_ip_instance jesd204_versal_gt_adapter_rx ${ip_name}/rx_adapt_${j} [list \ |
| 242 | + LINK_MODE $link_mode \ |
| 243 | + ] |
| 244 | + ad_connect ${ip_name}/rx_adapt_${j}/RX_GT_IP_Interface ${ip_name}/xcvr/INTF${rx_intf}_RX${j}_GT_IP_Interface |
| 245 | + |
| 246 | + create_bd_intf_pin -mode Master -vlnv xilinx.com:display_jesd204:jesd204_rx_bus_rtl:1.0 ${ip_name}/rx${j} |
| 247 | + ad_connect ${ip_name}/rx${j} ${ip_name}/rx_adapt_${j}/RX |
| 248 | + ad_connect ${ip_name}/rx_adapt_${j}/usr_clk ${ip_name}/xcvr/INTF${rx_intf}_rx_usrclk |
| 249 | + ad_connect ${ip_name}/rx_adapt_${j}/en_char_align ${ip_name}/en_char_align |
| 250 | + } |
| 251 | + } |
| 252 | + |
| 253 | + if {$intf_cfg != "RX"} { |
| 254 | + ad_ip_instance bufg_gt ${ip_name}/bufg_gt_tx |
| 255 | + ad_connect ${ip_name}/xcvr/INTF${tx_intf}_tx_clr_out ${ip_name}/bufg_gt_tx/gt_bufgtclr |
| 256 | + ad_connect ${ip_name}/xcvr/QUAD0_TX0_outclk ${ip_name}/bufg_gt_tx/outclk |
| 257 | + ad_connect ${ip_name}/bufg_gt_tx/usrclk ${ip_name}/txusrclk_out |
| 258 | + |
| 259 | + for {set j 0} {$j < $tx_quads} {incr j} { |
| 260 | + create_bd_pin -dir O -from 3 -to 0 ${ip_name}/tx_${j}_p |
| 261 | + create_bd_pin -dir O -from 3 -to 0 ${ip_name}/tx_${j}_n |
| 262 | + ad_connect ${ip_name}/xcvr/QUAD${j}_txp ${ip_name}/tx_${j}_p |
| 263 | + ad_connect ${ip_name}/xcvr/QUAD${j}_txn ${ip_name}/tx_${j}_n |
| 264 | + } |
| 265 | + |
| 266 | + for {set j 0} {$j < $tx_no_lanes} {incr j} { |
| 267 | + ad_ip_instance jesd204_versal_gt_adapter_tx ${ip_name}/tx_adapt_${j} [list \ |
| 268 | + LINK_MODE $link_mode \ |
| 269 | + ] |
| 270 | + ad_connect ${ip_name}/tx_adapt_${j}/TX_GT_IP_Interface ${ip_name}/xcvr/INTF${tx_intf}_TX${j}_GT_IP_Interface |
| 271 | + |
| 272 | + create_bd_intf_pin -mode Slave -vlnv xilinx.com:display_jesd204:jesd204_tx_bus_rtl:1.0 ${ip_name}/tx${j} |
| 273 | + ad_connect ${ip_name}/tx${j} ${ip_name}/tx_adapt_${j}/TX |
| 274 | + ad_connect ${ip_name}/tx_adapt_${j}/usr_clk ${ip_name}/xcvr/INTF${tx_intf}_tx_usrclk |
| 275 | + } |
| 276 | + } |
| 277 | + |
| 278 | + # Reset signals |
| 279 | + create_bd_pin -dir I ${ip_name}/gtreset_in |
| 280 | + create_bd_pin -dir O ${ip_name}/gtpowergood |
| 281 | + if {$intf_cfg != "TX"} { |
| 282 | + create_bd_pin -dir I ${ip_name}/gtreset_rx_pll_and_datapath |
| 283 | + create_bd_pin -dir I ${ip_name}/gtreset_rx_datapath |
| 284 | + create_bd_pin -dir O ${ip_name}/rx_resetdone |
| 285 | + } |
| 286 | + if {$intf_cfg != "RX"} { |
| 287 | + create_bd_pin -dir I ${ip_name}/gtreset_tx_pll_and_datapath |
| 288 | + create_bd_pin -dir I ${ip_name}/gtreset_tx_datapath |
| 289 | + create_bd_pin -dir O ${ip_name}/tx_resetdone |
| 290 | + } |
| 291 | + |
| 292 | + create_bd_cell -type module -reference sync_bits ${ip_name}/gtreset_sync |
| 293 | + ad_connect ${ip_name}/s_axi_clk ${ip_name}/gtreset_sync/out_clk |
| 294 | + ad_connect ${ip_name}/s_axi_resetn ${ip_name}/gtreset_sync/out_resetn |
| 295 | + ad_connect ${ip_name}/gtreset_in ${ip_name}/gtreset_sync/in_bits |
| 296 | + |
| 297 | + |
| 298 | + ad_connect ${ip_name}/gtreset_sync/out_bits ${ip_name}/xcvr/INTF${rx_intf}_rst_all_in |
| 299 | + if {$rx_intf != $tx_intf} { |
| 300 | + ad_connect ${ip_name}/gtreset_sync/out_bits ${ip_name}/xcvr/INTF${tx_intf}_rst_all_in |
| 301 | + } |
| 302 | + |
| 303 | + foreach port {pll_and_datapath datapath} { |
| 304 | + foreach rx_tx {rx tx} { |
| 305 | + if {($rx_tx == "rx" && $intf_cfg == "TX") || ($rx_tx == "tx" && $intf_cfg == "RX")} { |
| 306 | + continue |
| 307 | + } |
| 308 | + set intf [expr {$rx_tx == "rx" ? $rx_intf : $tx_intf}] |
| 309 | + create_bd_cell -type module -reference sync_bits ${ip_name}/gtreset_${rx_tx}_${port}_sync |
| 310 | + ad_connect ${ip_name}/s_axi_clk ${ip_name}/gtreset_${rx_tx}_${port}_sync/out_clk |
| 311 | + ad_connect ${ip_name}/s_axi_resetn ${ip_name}/gtreset_${rx_tx}_${port}_sync/out_resetn |
| 312 | + ad_connect ${ip_name}/gtreset_${rx_tx}_${port} ${ip_name}/gtreset_${rx_tx}_${port}_sync/in_bits |
| 313 | + ad_connect ${ip_name}/gtreset_${rx_tx}_${port}_sync/out_bits ${ip_name}/xcvr/INTF${intf}_rst_${rx_tx}_${port}_in |
| 314 | + } |
| 315 | + } |
| 316 | + |
| 317 | + ad_connect ${ip_name}/xcvr/gtpowergood ${ip_name}/gtpowergood |
| 318 | + if {$intf_cfg != "TX"} { |
| 319 | + ad_connect ${ip_name}/xcvr/INTF${rx_intf}_rst_rx_done_out ${ip_name}/rx_resetdone |
| 320 | + } |
| 321 | + if {$intf_cfg != "RX"} { |
| 322 | + ad_connect ${ip_name}/xcvr/INTF${tx_intf}_rst_tx_done_out ${ip_name}/tx_resetdone |
| 323 | + } |
| 324 | + |
| 325 | + # AXI interface |
| 326 | + ad_connect ${ip_name}/s_axi_clk ${ip_name}/xcvr/gtwiz_freerun_clk |
| 327 | + for {set j 0} {$j < $num_quads} {incr j} { |
| 328 | + ad_connect ${ip_name}/s_axi_resetn ${ip_name}/xcvr/QUAD${j}_s_axi_lite_resetn |
| 329 | + |
| 330 | + create_bd_intf_pin -mode Slave -vlnv xilinx.com:interface:aximm_rtl:1.0 ${ip_name}/s_axi_${j} |
| 331 | + ad_connect ${ip_name}/s_axi_${j} ${ip_name}/xcvr/Quad${j}_AXI_LITE |
| 332 | + } |
| 333 | +} |
0 commit comments