From b6be624bdb7f2ec421a8e3f2ce191c6f0529bbfc Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sat, 22 Feb 2025 23:15:24 -0800 Subject: [PATCH] example/KCU105: Add support for 10GBASE-R on KCU105 Signed-off-by: Alex Forencich --- example/KCU105/fpga/README.md | 2 + example/KCU105/fpga/fpga.xdc | 20 +- example/KCU105/fpga/fpga_10g/Makefile | 48 ++ example/KCU105/fpga/fpga_1g/Makefile | 2 +- example/KCU105/fpga/rtl/fpga.sv | 345 ++++++----- example/KCU105/fpga/rtl/fpga_core.sv | 562 ++++++++++++++---- example/KCU105/fpga/tb/fpga_core/Makefile | 6 +- example/KCU105/fpga/tb/fpga_core/baser.py | 1 + .../fpga/tb/fpga_core/test_fpga_core.py | 121 +++- 9 files changed, 786 insertions(+), 321 deletions(-) create mode 100644 example/KCU105/fpga/fpga_10g/Makefile create mode 120000 example/KCU105/fpga/tb/fpga_core/baser.py diff --git a/example/KCU105/fpga/README.md b/example/KCU105/fpga/README.md index df2e8c7..755ec90 100644 --- a/example/KCU105/fpga/README.md +++ b/example/KCU105/fpga/README.md @@ -12,12 +12,14 @@ The design places looped-back MACs on the BASE-T port and SFP+ cages, as well as * Looped-back MAC via SGMII via Xilinx PCS/PMA core and LVDS IOSERDES * SFP+ cages * Looped-back 1000BASE-X via Xilinx PCS/PMA core and GTH transceiver + * Looped-back 10GBASE-R MAC via GTH transceiver ## Board details * FPGA: xcku040-ffva1156-2-e * 1000BASE-T PHY: Marvell 88E1111 via SGMII * 1000BASE-X PHY: Xilinx PCS/PMA core via GTH transceiver +* 10GBASE-R PHY: Soft PCS with GTH transceiver ## Licensing diff --git a/example/KCU105/fpga/fpga.xdc b/example/KCU105/fpga/fpga.xdc index bac1845..12b6cdf 100644 --- a/example/KCU105/fpga/fpga.xdc +++ b/example/KCU105/fpga/fpga.xdc @@ -155,14 +155,14 @@ set_input_delay 0 [get_ports {phy_int_n}] #set_input_delay 0 [get_ports {phy_mdio}] # SFP+ interface -set_property -dict {LOC T2 } [get_ports {sfp0_rx_p}] ;# MGTYRXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC T1 } [get_ports {sfp0_rx_n}] ;# MGTYRXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC U4 } [get_ports {sfp0_tx_p}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC U3 } [get_ports {sfp0_tx_n}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC V2 } [get_ports {sfp1_rx_p}] ;# MGTYRXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC V1 } [get_ports {sfp1_rx_n}] ;# MGTYRXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC W4 } [get_ports {sfp1_tx_p}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 -set_property -dict {LOC W3 } [get_ports {sfp1_tx_n}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC T2 } [get_ports {sfp_rx_p[0]}] ;# MGTYRXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC T1 } [get_ports {sfp_rx_n[0]}] ;# MGTYRXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC U4 } [get_ports {sfp_tx_p[0]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC U3 } [get_ports {sfp_tx_n[0]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC V2 } [get_ports {sfp_rx_p[1]}] ;# MGTYRXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC V1 } [get_ports {sfp_rx_n[1]}] ;# MGTYRXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC W4 } [get_ports {sfp_tx_p[1]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 +set_property -dict {LOC W3 } [get_ports {sfp_tx_n[1]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 set_property -dict {LOC P6 } [get_ports sfp_mgt_refclk_0_p] ;# MGTREFCLK0P_227 from U32 Si570 via U104 Si53340 set_property -dict {LOC P5 } [get_ports sfp_mgt_refclk_0_n] ;# MGTREFCLK0N_227 from U32 Si570 via U104 Si53340 #set_property -dict {LOC M6 } [get_ports sfp_mgt_refclk_1_p] ;# MGTREFCLK1P_227 from U57 Si5328B @@ -170,8 +170,8 @@ set_property -dict {LOC P5 } [get_ports sfp_mgt_refclk_0_n] ;# MGTREFCLK0N_227 #set_property -dict {LOC AG11 IOSTANDARD LVDS} [get_ports sfp_recclk_p] ;# to U57 CKIN1 SI5328 #set_property -dict {LOC AH11 IOSTANDARD LVDS} [get_ports sfp_recclk_n] ;# to U57 CKIN1 SI5328 -set_property -dict {LOC AL8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp0_tx_disable_b}] -set_property -dict {LOC D28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp1_tx_disable_b}] +set_property -dict {LOC AL8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_tx_disable_b[0]}] +set_property -dict {LOC D28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_tx_disable_b[1]}] # 156.25 MHz MGT reference clock create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports sfp_mgt_refclk_0_p] diff --git a/example/KCU105/fpga/fpga_10g/Makefile b/example/KCU105/fpga/fpga_10g/Makefile new file mode 100644 index 0000000..66d7c33 --- /dev/null +++ b/example/KCU105/fpga/fpga_10g/Makefile @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (c) 2025 FPGA Ninja, LLC +# +# Authors: +# - Alex Forencich +# + +# FPGA settings +FPGA_PART = xcku040-ffva1156-2-e +FPGA_TOP = fpga +FPGA_ARCH = kintexu + +# Files for synthesis +SYN_FILES = ../rtl/fpga.sv +SYN_FILES += ../rtl/fpga_core.sv +SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f +SYN_FILES += ../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us.f +SYN_FILES += ../lib/taxi/rtl/lss/taxi_uart.f +SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_reset.sv +SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_signal.sv +SYN_FILES += ../lib/taxi/rtl/io/taxi_debounce_switch.sv + +# XDC files +XDC_FILES = ../fpga.xdc +XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_fifo.tcl +XDC_FILES += ../lib/taxi/syn/vivado/taxi_axis_async_fifo.tcl +XDC_FILES += ../lib/taxi/syn/vivado/taxi_sync_reset.tcl + +# IP +IP_TCL_FILES = ../ip/sgmii_pcs_pma_0.tcl +IP_TCL_FILES += ../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us_gth_10g_156.tcl + +# Configuration +CONFIG_TCL_FILES = ./config.tcl + +include ../common/vivado.mk + +program: $(PROJECT).bit + echo "open_hw_manager" > program.tcl + echo "connect_hw_server" >> program.tcl + echo "open_hw_target" >> program.tcl + echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl + echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl + echo "set_property PROGRAM.FILE {$(PROJECT).bit} [current_hw_device]" >> program.tcl + echo "program_hw_devices [current_hw_device]" >> program.tcl + echo "exit" >> program.tcl + vivado -nojournal -nolog -mode batch -source program.tcl diff --git a/example/KCU105/fpga/fpga_1g/Makefile b/example/KCU105/fpga/fpga_1g/Makefile index 0994f06..adbf476 100644 --- a/example/KCU105/fpga/fpga_1g/Makefile +++ b/example/KCU105/fpga/fpga_1g/Makefile @@ -32,7 +32,7 @@ IP_TCL_FILES += ../ip/basex_pcs_pma_0.tcl IP_TCL_FILES += ../ip/basex_pcs_pma_1.tcl # Configuration -# CONFIG_TCL_FILES = ./config.tcl +CONFIG_TCL_FILES = ./config.tcl include ../common/vivado.mk diff --git a/example/KCU105/fpga/rtl/fpga.sv b/example/KCU105/fpga/rtl/fpga.sv index a0f74ec..0a9d3ba 100644 --- a/example/KCU105/fpga/rtl/fpga.sv +++ b/example/KCU105/fpga/rtl/fpga.sv @@ -15,7 +15,17 @@ Authors: /* * FPGA top-level module */ -module fpga +module fpga # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter string VENDOR = "XILINX", + // device family + parameter string FAMILY = "kintexu", + // SFP rate selection (0 for 1G, 1 for 10G) + parameter logic SFP_RATE = 1'b1 +) ( /* * Clock: 125MHz LVDS @@ -59,19 +69,14 @@ module fpga /* * Ethernet: SFP+ */ - input wire logic sfp0_rx_p, - input wire logic sfp0_rx_n, - output wire logic sfp0_tx_p, - output wire logic sfp0_tx_n, - input wire logic sfp1_rx_p, - input wire logic sfp1_rx_n, - output wire logic sfp1_tx_p, - output wire logic sfp1_tx_n, + input wire logic [1:0] sfp_rx_p, + input wire logic [1:0] sfp_rx_n, + output wire logic [1:0] sfp_tx_p, + output wire logic [1:0] sfp_tx_n, input wire logic sfp_mgt_refclk_0_p, input wire logic sfp_mgt_refclk_0_n, - output wire logic sfp0_tx_disable_b, - output wire logic sfp1_tx_disable_b + output wire logic [1:0] sfp_tx_disable_b ); // Clock and reset @@ -346,176 +351,186 @@ eth_pcspma ( .signal_detect (1'b1) ); -// 1000BASE-X SFP +// SFP+ +wire [1:0] sfp_tx_p_int; +wire [1:0] sfp_tx_n_int; + wire sfp0_gmii_clk_int; wire sfp0_gmii_rst_int; wire sfp0_gmii_clk_en_int; wire [7:0] sfp0_gmii_txd_int; -wire sfp0_gmii_tx_en_int; +wire sfp0_gmii_tx_en_int = 1'b1; wire sfp0_gmii_tx_er_int; wire [7:0] sfp0_gmii_rxd_int; wire sfp0_gmii_rx_dv_int; wire sfp0_gmii_rx_er_int; -wire sfp0_gmii_gtrefclk; -wire sfp0_gmii_txuserclk; -wire sfp0_gmii_txuserclk2; -wire sfp0_gmii_rxuserclk; -wire sfp0_gmii_rxuserclk2; -wire sfp0_gmii_resetdone; -wire sfp0_gmii_pmareset; -wire sfp0_gmii_mmcm_locked; - -assign sfp0_gmii_clk_int = sfp0_gmii_txuserclk2; - -taxi_sync_reset #( - .N(4) -) -sync_reset_sfp0_inst ( - .clk(sfp0_gmii_clk_int), - .rst(rst_125mhz_int || !sfp0_gmii_resetdone), - .out(sfp0_gmii_rst_int) -); - wire [15:0] sfp0_status_vect; -wire sfp0_status_link_status = sfp0_status_vect[0]; -wire sfp0_status_link_synchronization = sfp0_status_vect[1]; -wire sfp0_status_rudi_c = sfp0_status_vect[2]; -wire sfp0_status_rudi_i = sfp0_status_vect[3]; -wire sfp0_status_rudi_invalid = sfp0_status_vect[4]; -wire sfp0_status_rxdisperr = sfp0_status_vect[5]; -wire sfp0_status_rxnotintable = sfp0_status_vect[6]; -wire sfp0_status_phy_link_status = sfp0_status_vect[7]; -wire [1:0] sfp0_status_remote_fault_encdg = sfp0_status_vect[9:8]; -wire [1:0] sfp0_status_speed = sfp0_status_vect[11:10]; -wire sfp0_status_duplex = sfp0_status_vect[12]; -wire sfp0_status_remote_fault = sfp0_status_vect[13]; -wire [1:0] sfp0_status_pause = sfp0_status_vect[15:14]; - -wire [4:0] sfp0_config_vect; - -assign sfp0_config_vect[4] = 1'b0; // autonegotiation enable -assign sfp0_config_vect[3] = 1'b0; // isolate -assign sfp0_config_vect[2] = 1'b0; // power down -assign sfp0_config_vect[1] = 1'b0; // loopback enable -assign sfp0_config_vect[0] = 1'b0; // unidirectional enable - -basex_pcs_pma_0 -sfp0_pcspma ( - .gtrefclk_p(sfp_mgt_refclk_0_p), - .gtrefclk_n(sfp_mgt_refclk_0_n), - .gtrefclk_out(sfp0_gmii_gtrefclk), - .txn(sfp0_tx_n), - .txp(sfp0_tx_p), - .rxn(sfp0_rx_n), - .rxp(sfp0_rx_p), - .independent_clock_bufg(clk_62mhz_int), - .userclk_out(sfp0_gmii_txuserclk), - .userclk2_out(sfp0_gmii_txuserclk2), - .rxuserclk_out(sfp0_gmii_rxuserclk), - .rxuserclk2_out(sfp0_gmii_rxuserclk2), - .gtpowergood(), - .resetdone(sfp0_gmii_resetdone), - .pma_reset_out(sfp0_gmii_pmareset), - .mmcm_locked_out(sfp0_gmii_mmcm_locked), - .gmii_txd(sfp0_gmii_txd_int), - .gmii_tx_en(sfp0_gmii_tx_en_int), - .gmii_tx_er(sfp0_gmii_tx_er_int), - .gmii_rxd(sfp0_gmii_rxd_int), - .gmii_rx_dv(sfp0_gmii_rx_dv_int), - .gmii_rx_er(sfp0_gmii_rx_er_int), - .gmii_isolate(), - .configuration_vector(sfp0_config_vect), - .status_vector(sfp0_status_vect), - .reset(rst_125mhz_int), - .signal_detect(1'b1) -); - -assign sfp0_gmii_clk_en_int = 1'b1; - wire sfp1_gmii_clk_int; wire sfp1_gmii_rst_int; wire sfp1_gmii_clk_en_int; wire [7:0] sfp1_gmii_txd_int; -wire sfp1_gmii_tx_en_int; +wire sfp1_gmii_tx_en_int = 1'b1; wire sfp1_gmii_tx_er_int; wire [7:0] sfp1_gmii_rxd_int; wire sfp1_gmii_rx_dv_int; wire sfp1_gmii_rx_er_int; -wire sfp1_gmii_txuserclk2 = sfp0_gmii_txuserclk2; -wire sfp1_gmii_resetdone; - -assign sfp1_gmii_clk_int = sfp1_gmii_txuserclk2; - -taxi_sync_reset #( - .N(4) -) -sync_reset_sfp1_inst ( - .clk(sfp1_gmii_clk_int), - .rst(rst_125mhz_int || !sfp1_gmii_resetdone), - .out(sfp1_gmii_rst_int) -); - wire [15:0] sfp1_status_vect; -wire sfp1_status_link_status = sfp1_status_vect[0]; -wire sfp1_status_link_synchronization = sfp1_status_vect[1]; -wire sfp1_status_rudi_c = sfp1_status_vect[2]; -wire sfp1_status_rudi_i = sfp1_status_vect[3]; -wire sfp1_status_rudi_invalid = sfp1_status_vect[4]; -wire sfp1_status_rxdisperr = sfp1_status_vect[5]; -wire sfp1_status_rxnotintable = sfp1_status_vect[6]; -wire sfp1_status_phy_link_status = sfp1_status_vect[7]; -wire [1:0] sfp1_status_remote_fault_encdg = sfp1_status_vect[9:8]; -wire [1:0] sfp1_status_speed = sfp1_status_vect[11:10]; -wire sfp1_status_duplex = sfp1_status_vect[12]; -wire sfp1_status_remote_fault = sfp1_status_vect[13]; -wire [1:0] sfp1_status_pause = sfp1_status_vect[15:14]; +if (SFP_RATE == 0) begin : sfp_phy + // 1000BASE-X -wire [4:0] sfp1_config_vect; + wire sfp0_gmii_gtrefclk; + wire sfp0_gmii_txuserclk; + wire sfp0_gmii_txuserclk2; + wire sfp0_gmii_rxuserclk; + wire sfp0_gmii_rxuserclk2; + wire sfp0_gmii_resetdone; + wire sfp0_gmii_pmareset; + wire sfp0_gmii_mmcm_locked; -assign sfp1_config_vect[4] = 1'b0; // autonegotiation enable -assign sfp1_config_vect[3] = 1'b0; // isolate -assign sfp1_config_vect[2] = 1'b0; // power down -assign sfp1_config_vect[1] = 1'b0; // loopback enable -assign sfp1_config_vect[0] = 1'b0; // unidirectional enable + assign sfp0_gmii_clk_int = sfp0_gmii_txuserclk2; -basex_pcs_pma_1 -sfp1_pcspma ( - .gtrefclk(sfp0_gmii_gtrefclk), - .txn(sfp1_tx_n), - .txp(sfp1_tx_p), - .rxn(sfp1_rx_n), - .rxp(sfp1_rx_p), - .independent_clock_bufg(clk_62mhz_int), - .txoutclk(), - .gtpowergood(), - .rxoutclk(), - .resetdone(sfp1_gmii_resetdone), - .cplllock(), - .mmcm_reset(), - .userclk(sfp0_gmii_txuserclk), - .userclk2(sfp0_gmii_txuserclk2), - .pma_reset(sfp0_gmii_pmareset), - .mmcm_locked(sfp0_gmii_mmcm_locked), - .rxuserclk(sfp0_gmii_txuserclk), - .rxuserclk2(sfp0_gmii_txuserclk2), - .gmii_txd(sfp1_gmii_txd_int), - .gmii_tx_en(sfp1_gmii_tx_en_int), - .gmii_tx_er(sfp1_gmii_tx_er_int), - .gmii_rxd(sfp1_gmii_rxd_int), - .gmii_rx_dv(sfp1_gmii_rx_dv_int), - .gmii_rx_er(sfp1_gmii_rx_er_int), - .gmii_isolate(), - .configuration_vector(sfp1_config_vect), - .status_vector(sfp1_status_vect), - .reset(rst_125mhz_int), - .signal_detect(1'b1) -); + taxi_sync_reset #( + .N(4) + ) + sync_reset_sfp0_inst ( + .clk(sfp0_gmii_clk_int), + .rst(rst_125mhz_int || !sfp0_gmii_resetdone), + .out(sfp0_gmii_rst_int) + ); -assign sfp1_gmii_clk_en_int = 1'b1; + wire sfp0_status_link_status = sfp0_status_vect[0]; + wire sfp0_status_link_synchronization = sfp0_status_vect[1]; + wire sfp0_status_rudi_c = sfp0_status_vect[2]; + wire sfp0_status_rudi_i = sfp0_status_vect[3]; + wire sfp0_status_rudi_invalid = sfp0_status_vect[4]; + wire sfp0_status_rxdisperr = sfp0_status_vect[5]; + wire sfp0_status_rxnotintable = sfp0_status_vect[6]; + wire sfp0_status_phy_link_status = sfp0_status_vect[7]; + wire [1:0] sfp0_status_remote_fault_encdg = sfp0_status_vect[9:8]; + wire [1:0] sfp0_status_speed = sfp0_status_vect[11:10]; + wire sfp0_status_duplex = sfp0_status_vect[12]; + wire sfp0_status_remote_fault = sfp0_status_vect[13]; + wire [1:0] sfp0_status_pause = sfp0_status_vect[15:14]; + + wire [4:0] sfp0_config_vect; + + assign sfp0_config_vect[4] = 1'b0; // autonegotiation enable + assign sfp0_config_vect[3] = 1'b0; // isolate + assign sfp0_config_vect[2] = 1'b0; // power down + assign sfp0_config_vect[1] = 1'b0; // loopback enable + assign sfp0_config_vect[0] = 1'b0; // unidirectional enable + + basex_pcs_pma_0 + sfp0_pcspma ( + .gtrefclk_p(sfp_mgt_refclk_0_p), + .gtrefclk_n(sfp_mgt_refclk_0_n), + .gtrefclk_out(sfp0_gmii_gtrefclk), + .txn(sfp_tx_n[0]), + .txp(sfp_tx_p[0]), + .rxn(sfp_rx_n[0]), + .rxp(sfp_rx_p[0]), + .independent_clock_bufg(clk_62mhz_int), + .userclk_out(sfp0_gmii_txuserclk), + .userclk2_out(sfp0_gmii_txuserclk2), + .rxuserclk_out(sfp0_gmii_rxuserclk), + .rxuserclk2_out(sfp0_gmii_rxuserclk2), + .gtpowergood(), + .resetdone(sfp0_gmii_resetdone), + .pma_reset_out(sfp0_gmii_pmareset), + .mmcm_locked_out(sfp0_gmii_mmcm_locked), + .gmii_txd(sfp0_gmii_txd_int), + .gmii_tx_en(sfp0_gmii_tx_en_int), + .gmii_tx_er(sfp0_gmii_tx_er_int), + .gmii_rxd(sfp0_gmii_rxd_int), + .gmii_rx_dv(sfp0_gmii_rx_dv_int), + .gmii_rx_er(sfp0_gmii_rx_er_int), + .gmii_isolate(), + .configuration_vector(sfp0_config_vect), + .status_vector(sfp0_status_vect), + .reset(rst_125mhz_int), + .signal_detect(1'b1) + ); + + wire sfp1_gmii_txuserclk2 = sfp0_gmii_txuserclk2; + wire sfp1_gmii_resetdone; + + assign sfp1_gmii_clk_int = sfp1_gmii_txuserclk2; + + taxi_sync_reset #( + .N(4) + ) + sync_reset_sfp1_inst ( + .clk(sfp1_gmii_clk_int), + .rst(rst_125mhz_int || !sfp1_gmii_resetdone), + .out(sfp1_gmii_rst_int) + ); + + wire sfp1_status_link_status = sfp1_status_vect[0]; + wire sfp1_status_link_synchronization = sfp1_status_vect[1]; + wire sfp1_status_rudi_c = sfp1_status_vect[2]; + wire sfp1_status_rudi_i = sfp1_status_vect[3]; + wire sfp1_status_rudi_invalid = sfp1_status_vect[4]; + wire sfp1_status_rxdisperr = sfp1_status_vect[5]; + wire sfp1_status_rxnotintable = sfp1_status_vect[6]; + wire sfp1_status_phy_link_status = sfp1_status_vect[7]; + wire [1:0] sfp1_status_remote_fault_encdg = sfp1_status_vect[9:8]; + wire [1:0] sfp1_status_speed = sfp1_status_vect[11:10]; + wire sfp1_status_duplex = sfp1_status_vect[12]; + wire sfp1_status_remote_fault = sfp1_status_vect[13]; + wire [1:0] sfp1_status_pause = sfp1_status_vect[15:14]; + + wire [4:0] sfp1_config_vect; + + assign sfp1_config_vect[4] = 1'b0; // autonegotiation enable + assign sfp1_config_vect[3] = 1'b0; // isolate + assign sfp1_config_vect[2] = 1'b0; // power down + assign sfp1_config_vect[1] = 1'b0; // loopback enable + assign sfp1_config_vect[0] = 1'b0; // unidirectional enable + + basex_pcs_pma_1 + sfp1_pcspma ( + .gtrefclk(sfp0_gmii_gtrefclk), + .txn(sfp_tx_n[1]), + .txp(sfp_tx_p[1]), + .rxn(sfp_rx_n[1]), + .rxp(sfp_rx_p[1]), + .independent_clock_bufg(clk_62mhz_int), + .txoutclk(), + .gtpowergood(), + .rxoutclk(), + .resetdone(sfp1_gmii_resetdone), + .cplllock(), + .mmcm_reset(), + .userclk(sfp0_gmii_txuserclk), + .userclk2(sfp0_gmii_txuserclk2), + .pma_reset(sfp0_gmii_pmareset), + .mmcm_locked(sfp0_gmii_mmcm_locked), + .rxuserclk(sfp0_gmii_txuserclk), + .rxuserclk2(sfp0_gmii_txuserclk2), + .gmii_txd(sfp1_gmii_txd_int), + .gmii_tx_en(sfp1_gmii_tx_en_int), + .gmii_tx_er(sfp1_gmii_tx_er_int), + .gmii_rxd(sfp1_gmii_rxd_int), + .gmii_rx_dv(sfp1_gmii_rx_dv_int), + .gmii_rx_er(sfp1_gmii_rx_er_int), + .gmii_isolate(), + .configuration_vector(sfp1_config_vect), + .status_vector(sfp1_status_vect), + .reset(rst_125mhz_int), + .signal_detect(1'b1) + ); + +end else begin + // 10GBASE-R + + assign sfp_tx_p = sfp_tx_p_int; + assign sfp_tx_n = sfp_tx_n_int; + +end // SGMII interface debug: // SW12:1 (sw[3]) off for payload byte, on for status vector @@ -525,7 +540,12 @@ assign sfp1_gmii_clk_en_int = 1'b1; wire [15:0] sel_sv = sw[2] ? (sw[1] ? sfp1_status_vect : sfp0_status_vect) : sgmii_status_vect; assign led = sw[3] ? (sw[0] ? sel_sv[15:8] : sel_sv[7:0]) : led_int; -fpga_core +fpga_core #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + .SFP_RATE(SFP_RATE) +) core_inst ( /* * Clock: 125MHz @@ -569,8 +589,15 @@ core_inst ( .phy_int_n(phy_int_n), /* - * Ethernet: 1000BASE-X SFP + * Ethernet: SFP+ */ + .sfp_rx_p(sfp_rx_p), + .sfp_rx_n(sfp_rx_n), + .sfp_tx_p(sfp_tx_p_int), + .sfp_tx_n(sfp_tx_n_int), + .sfp_mgt_refclk_0_p(sfp_mgt_refclk_0_p), + .sfp_mgt_refclk_0_n(sfp_mgt_refclk_0_n), + .sfp0_gmii_clk(sfp0_gmii_clk_int), .sfp0_gmii_rst(sfp0_gmii_rst_int), .sfp0_gmii_clk_en(sfp0_gmii_clk_en_int), @@ -580,7 +607,6 @@ core_inst ( .sfp0_gmii_txd(sfp0_gmii_txd_int), .sfp0_gmii_tx_en(sfp0_gmii_tx_en_int), .sfp0_gmii_tx_er(sfp0_gmii_tx_er_int), - .sfp0_tx_disable_b(sfp0_tx_disable_b), .sfp1_gmii_clk(sfp1_gmii_clk_int), .sfp1_gmii_rst(sfp1_gmii_rst_int), @@ -591,7 +617,8 @@ core_inst ( .sfp1_gmii_txd(sfp1_gmii_txd_int), .sfp1_gmii_tx_en(sfp1_gmii_tx_en_int), .sfp1_gmii_tx_er(sfp1_gmii_tx_er_int), - .sfp1_tx_disable_b(sfp1_tx_disable_b) + + .sfp_tx_disable_b(sfp_tx_disable_b) ); endmodule diff --git a/example/KCU105/fpga/rtl/fpga_core.sv b/example/KCU105/fpga/rtl/fpga_core.sv index 3ceb98b..bf389be 100644 --- a/example/KCU105/fpga/rtl/fpga_core.sv +++ b/example/KCU105/fpga/rtl/fpga_core.sv @@ -15,7 +15,17 @@ Authors: /* * FPGA core logic */ -module fpga_core +module fpga_core # +( + // simulation (set to avoid vendor primitives) + parameter logic SIM = 1'b0, + // vendor ("GENERIC", "XILINX", "ALTERA") + parameter string VENDOR = "XILINX", + // device family + parameter string FAMILY = "kintexu", + // SFP rate selection (0 for 1G, 1 for 10G) + parameter logic SFP_RATE = 1'b1 +) ( /* * Clock: 125MHz @@ -59,8 +69,16 @@ module fpga_core input wire logic phy_int_n, /* - * Ethernet: 1000BASE-X SFP + * Ethernet: SFP+ */ + input wire logic [1:0] sfp_rx_p, + input wire logic [1:0] sfp_rx_n, + output wire logic [1:0] sfp_tx_p, + output wire logic [1:0] sfp_tx_n, + input wire logic sfp_mgt_refclk_0_p, + input wire logic sfp_mgt_refclk_0_n, + + input wire logic sfp0_gmii_clk, input wire logic sfp0_gmii_rst, input wire logic sfp0_gmii_clk_en, @@ -70,7 +88,6 @@ module fpga_core output wire logic [7:0] sfp0_gmii_txd, output wire logic sfp0_gmii_tx_en, output wire logic sfp0_gmii_tx_er, - output wire logic sfp0_tx_disable_b, input wire logic sfp1_gmii_clk, input wire logic sfp1_gmii_rst, @@ -81,7 +98,8 @@ module fpga_core output wire logic [7:0] sfp1_gmii_txd, output wire logic sfp1_gmii_tx_en, output wire logic sfp1_gmii_tx_er, - output wire logic sfp1_tx_disable_b + + output wire logic [1:0] sfp_tx_disable_b ); assign led = sw; @@ -199,146 +217,434 @@ eth_mac_inst ( ); // SFP+ -assign sfp0_tx_disable_b = 1'b1; -assign sfp1_tx_disable_b = 1'b1; +assign sfp_tx_disable_b = '1; -taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp0_eth(); -taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp0_tx_cpl(); +if (SFP_RATE == 0) begin : sfp_mac -taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp1_eth(); -taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp1_tx_cpl(); + taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp0_eth(); + taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp0_tx_cpl(); -taxi_eth_mac_1g_fifo #( - .PADDING_EN(1), - .MIN_FRAME_LEN(64), - .TX_FIFO_DEPTH(16384), - .TX_FRAME_FIFO(1), - .RX_FIFO_DEPTH(16384), - .RX_FRAME_FIFO(1) -) -sfp0_eth_mac_inst ( - .rx_clk(sfp0_gmii_clk), - .rx_rst(sfp0_gmii_rst), - .tx_clk(sfp0_gmii_clk), - .tx_rst(sfp0_gmii_rst), - .logic_clk(clk), - .logic_rst(rst), + taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp1_eth(); + taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp1_tx_cpl(); - /* - * Transmit interface (AXI stream) - */ - .s_axis_tx(axis_sfp0_eth), - .m_axis_tx_cpl(axis_sfp0_tx_cpl), + taxi_eth_mac_1g_fifo #( + .PADDING_EN(1), + .MIN_FRAME_LEN(64), + .TX_FIFO_DEPTH(16384), + .TX_FRAME_FIFO(1), + .RX_FIFO_DEPTH(16384), + .RX_FRAME_FIFO(1) + ) + sfp0_eth_mac_inst ( + .rx_clk(sfp0_gmii_clk), + .rx_rst(sfp0_gmii_rst), + .tx_clk(sfp0_gmii_clk), + .tx_rst(sfp0_gmii_rst), + .logic_clk(clk), + .logic_rst(rst), - /* - * Receive interface (AXI stream) - */ - .m_axis_rx(axis_sfp0_eth), + /* + * Transmit interface (AXI stream) + */ + .s_axis_tx(axis_sfp0_eth), + .m_axis_tx_cpl(axis_sfp0_tx_cpl), - /* - * GMII interface - */ - .gmii_rxd(sfp0_gmii_rxd), - .gmii_rx_dv(sfp0_gmii_rx_dv), - .gmii_rx_er(sfp0_gmii_rx_er), - .gmii_txd(sfp0_gmii_txd), - .gmii_tx_en(sfp0_gmii_tx_en), - .gmii_tx_er(sfp0_gmii_tx_er), + /* + * Receive interface (AXI stream) + */ + .m_axis_rx(axis_sfp0_eth), - /* - * Control - */ - .rx_clk_enable(sfp0_gmii_clk_en), - .tx_clk_enable(sfp0_gmii_clk_en), - .rx_mii_select(1'b0), - .tx_mii_select(1'b0), + /* + * GMII interface + */ + .gmii_rxd(sfp0_gmii_rxd), + .gmii_rx_dv(sfp0_gmii_rx_dv), + .gmii_rx_er(sfp0_gmii_rx_er), + .gmii_txd(sfp0_gmii_txd), + .gmii_tx_en(sfp0_gmii_tx_en), + .gmii_tx_er(sfp0_gmii_tx_er), - /* - * Status - */ - .tx_error_underflow(), - .tx_fifo_overflow(), - .tx_fifo_bad_frame(), - .tx_fifo_good_frame(), - .rx_error_bad_frame(), - .rx_error_bad_fcs(), - .rx_fifo_overflow(), - .rx_fifo_bad_frame(), - .rx_fifo_good_frame(), + /* + * Control + */ + .rx_clk_enable(sfp0_gmii_clk_en), + .tx_clk_enable(sfp0_gmii_clk_en), + .rx_mii_select(1'b0), + .tx_mii_select(1'b0), - /* - * Configuration - */ - .cfg_ifg(8'd12), - .cfg_tx_enable(1'b1), - .cfg_rx_enable(1'b1) -); + /* + * Status + */ + .tx_error_underflow(), + .tx_fifo_overflow(), + .tx_fifo_bad_frame(), + .tx_fifo_good_frame(), + .rx_error_bad_frame(), + .rx_error_bad_fcs(), + .rx_fifo_overflow(), + .rx_fifo_bad_frame(), + .rx_fifo_good_frame(), -taxi_eth_mac_1g_fifo #( - .PADDING_EN(1), - .MIN_FRAME_LEN(64), - .TX_FIFO_DEPTH(16384), - .TX_FRAME_FIFO(1), - .RX_FIFO_DEPTH(16384), - .RX_FRAME_FIFO(1) -) -sfp1_eth_mac_inst ( - .rx_clk(sfp1_gmii_clk), - .rx_rst(sfp1_gmii_rst), - .tx_clk(sfp1_gmii_clk), - .tx_rst(sfp1_gmii_rst), - .logic_clk(clk), - .logic_rst(rst), + /* + * Configuration + */ + .cfg_ifg(8'd12), + .cfg_tx_enable(1'b1), + .cfg_rx_enable(1'b1) + ); - /* - * Transmit interface (AXI stream) - */ - .s_axis_tx(axis_sfp1_eth), - .m_axis_tx_cpl(axis_sfp1_tx_cpl), + taxi_eth_mac_1g_fifo #( + .PADDING_EN(1), + .MIN_FRAME_LEN(64), + .TX_FIFO_DEPTH(16384), + .TX_FRAME_FIFO(1), + .RX_FIFO_DEPTH(16384), + .RX_FRAME_FIFO(1) + ) + sfp1_eth_mac_inst ( + .rx_clk(sfp1_gmii_clk), + .rx_rst(sfp1_gmii_rst), + .tx_clk(sfp1_gmii_clk), + .tx_rst(sfp1_gmii_rst), + .logic_clk(clk), + .logic_rst(rst), - /* - * Receive interface (AXI stream) - */ - .m_axis_rx(axis_sfp1_eth), + /* + * Transmit interface (AXI stream) + */ + .s_axis_tx(axis_sfp1_eth), + .m_axis_tx_cpl(axis_sfp1_tx_cpl), - /* - * GMII interface - */ - .gmii_rxd(sfp1_gmii_rxd), - .gmii_rx_dv(sfp1_gmii_rx_dv), - .gmii_rx_er(sfp1_gmii_rx_er), - .gmii_txd(sfp1_gmii_txd), - .gmii_tx_en(sfp1_gmii_tx_en), - .gmii_tx_er(sfp1_gmii_tx_er), + /* + * Receive interface (AXI stream) + */ + .m_axis_rx(axis_sfp1_eth), - /* - * Control - */ - .rx_clk_enable(sfp1_gmii_clk_en), - .tx_clk_enable(sfp1_gmii_clk_en), - .rx_mii_select(1'b0), - .tx_mii_select(1'b0), + /* + * GMII interface + */ + .gmii_rxd(sfp1_gmii_rxd), + .gmii_rx_dv(sfp1_gmii_rx_dv), + .gmii_rx_er(sfp1_gmii_rx_er), + .gmii_txd(sfp1_gmii_txd), + .gmii_tx_en(sfp1_gmii_tx_en), + .gmii_tx_er(sfp1_gmii_tx_er), - /* - * Status - */ - .tx_error_underflow(), - .tx_fifo_overflow(), - .tx_fifo_bad_frame(), - .tx_fifo_good_frame(), - .rx_error_bad_frame(), - .rx_error_bad_fcs(), - .rx_fifo_overflow(), - .rx_fifo_bad_frame(), - .rx_fifo_good_frame(), + /* + * Control + */ + .rx_clk_enable(sfp1_gmii_clk_en), + .tx_clk_enable(sfp1_gmii_clk_en), + .rx_mii_select(1'b0), + .tx_mii_select(1'b0), - /* - * Configuration - */ - .cfg_ifg(8'd12), - .cfg_tx_enable(1'b1), - .cfg_rx_enable(1'b1) -); + /* + * Status + */ + .tx_error_underflow(), + .tx_fifo_overflow(), + .tx_fifo_bad_frame(), + .tx_fifo_good_frame(), + .rx_error_bad_frame(), + .rx_error_bad_fcs(), + .rx_fifo_overflow(), + .rx_fifo_bad_frame(), + .rx_fifo_good_frame(), + + /* + * Configuration + */ + .cfg_ifg(8'd12), + .cfg_tx_enable(1'b1), + .cfg_rx_enable(1'b1) + ); + +end else begin : sfp_mac + + wire [1:0] sfp_tx_clk; + wire [1:0] sfp_tx_rst; + wire [1:0] sfp_rx_clk; + wire [1:0] sfp_rx_rst; + + wire [1:0] sfp_rx_status; + + wire sfp_gtpowergood; + + wire sfp_mgt_refclk_0; + wire sfp_mgt_refclk_0_int; + wire sfp_mgt_refclk_0_bufg; + + wire sfp_rst; + + taxi_axis_if #(.DATA_W(64), .ID_W(8)) axis_sfp_tx[1:0](); + taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[1:0](); + taxi_axis_if #(.DATA_W(64), .ID_W(8)) axis_sfp_rx[1:0](); + + if (SIM) begin + + assign sfp_gtpowergood = 1'b1; + + assign sfp_mgt_refclk_0 = sfp_mgt_refclk_0_p; + assign sfp_mgt_refclk_0_int = sfp_mgt_refclk_0_p; + assign sfp_mgt_refclk_0_bufg = sfp_mgt_refclk_0_int; + + end else begin + + IBUFDS_GTE3 ibufds_gte3_sfp_mgt_refclk_0_inst ( + .I (sfp_mgt_refclk_0_p), + .IB (sfp_mgt_refclk_0_n), + .CEB (1'b0), + .O (sfp_mgt_refclk_0), + .ODIV2 (sfp_mgt_refclk_0_int) + ); + + BUFG_GT bufg_gt_sfp_mgt_refclk_0_inst ( + .CE (sfp_gtpowergood), + .CEMASK (1'b1), + .CLR (1'b0), + .CLRMASK (1'b1), + .DIV (3'd0), + .I (sfp_mgt_refclk_0_int), + .O (sfp_mgt_refclk_0_bufg) + ); + + end + + taxi_sync_reset #( + .N(4) + ) + sfp_sync_reset_inst ( + .clk(sfp_mgt_refclk_0_bufg), + .rst(rst), + .out(sfp_rst) + ); + + taxi_eth_mac_25g_us #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + + .CNT(2), + + // GT type + .GT_TYPE("GTH"), + + // PHY parameters + .PADDING_EN(1'b1), + .DIC_EN(1'b1), + .MIN_FRAME_LEN(64), + .PTP_TS_EN(1'b0), + .PTP_TS_FMT_TOD(1'b1), + .PTP_TS_W(96), + .PRBS31_EN(1'b0), + .TX_SERDES_PIPELINE(1), + .RX_SERDES_PIPELINE(1), + .COUNT_125US(125000/6.4) + ) + sfp_mac_inst ( + .xcvr_ctrl_clk(clk), + .xcvr_ctrl_rst(sfp_rst), + + /* + * Common + */ + .xcvr_gtpowergood_out(sfp_gtpowergood), + .xcvr_gtrefclk00_in(sfp_mgt_refclk_0), + .xcvr_qpll0lock_out(), + .xcvr_qpll0clk_out(), + .xcvr_qpll0refclk_out(), + + /* + * Serial data + */ + .xcvr_txp(sfp_tx_p), + .xcvr_txn(sfp_tx_n), + .xcvr_rxp(sfp_rx_p), + .xcvr_rxn(sfp_rx_n), + + /* + * MAC clocks + */ + .rx_clk(sfp_rx_clk), + .rx_rst_in('0), + .rx_rst_out(sfp_rx_rst), + .tx_clk(sfp_tx_clk), + .tx_rst_in('0), + .tx_rst_out(sfp_tx_rst), + .ptp_sample_clk('0), + + /* + * Transmit interface (AXI stream) + */ + .s_axis_tx(axis_sfp_tx), + .m_axis_tx_cpl(axis_sfp_tx_cpl), + + /* + * Receive interface (AXI stream) + */ + .m_axis_rx(axis_sfp_rx), + + /* + * PTP clock + */ + .tx_ptp_ts('0), + .tx_ptp_ts_step('0), + .rx_ptp_ts('0), + .rx_ptp_ts_step('0), + + + /* + * Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE) + */ + .tx_lfc_req('0), + .tx_lfc_resend('0), + .rx_lfc_en('0), + .rx_lfc_req(), + .rx_lfc_ack('0), + + /* + * Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC) + */ + .tx_pfc_req('0), + .tx_pfc_resend('0), + .rx_pfc_en('0), + .rx_pfc_req(), + .rx_pfc_ack('0), + + /* + * Pause interface + */ + .tx_lfc_pause_en('0), + .tx_pause_req('0), + .tx_pause_ack(), + + /* + * Status + */ + .tx_start_packet(), + .tx_error_underflow(), + .rx_start_packet(), + .rx_error_count(), + .rx_error_bad_frame(), + .rx_error_bad_fcs(), + .rx_bad_block(), + .rx_sequence_error(), + .rx_block_lock(), + .rx_high_ber(), + .rx_status(sfp_rx_status), + .stat_tx_mcf(), + .stat_rx_mcf(), + .stat_tx_lfc_pkt(), + .stat_tx_lfc_xon(), + .stat_tx_lfc_xoff(), + .stat_tx_lfc_paused(), + .stat_tx_pfc_pkt(), + .stat_tx_pfc_xon(), + .stat_tx_pfc_xoff(), + .stat_tx_pfc_paused(), + .stat_rx_lfc_pkt(), + .stat_rx_lfc_xon(), + .stat_rx_lfc_xoff(), + .stat_rx_lfc_paused(), + .stat_rx_pfc_pkt(), + .stat_rx_pfc_xon(), + .stat_rx_pfc_xoff(), + .stat_rx_pfc_paused(), + + /* + * Configuration + */ + .cfg_ifg('{2{8'd12}}), + .cfg_tx_enable('1), + .cfg_rx_enable('1), + .cfg_tx_prbs31_enable('0), + .cfg_rx_prbs31_enable('0), + .cfg_mcf_rx_eth_dst_mcast('{2{48'h01_80_C2_00_00_01}}), + .cfg_mcf_rx_check_eth_dst_mcast('1), + .cfg_mcf_rx_eth_dst_ucast('{2{48'd0}}), + .cfg_mcf_rx_check_eth_dst_ucast('0), + .cfg_mcf_rx_eth_src('{2{48'd0}}), + .cfg_mcf_rx_check_eth_src('0), + .cfg_mcf_rx_eth_type('{2{16'h8808}}), + .cfg_mcf_rx_opcode_lfc('{2{16'h0001}}), + .cfg_mcf_rx_check_opcode_lfc('1), + .cfg_mcf_rx_opcode_pfc('{2{16'h0101}}), + .cfg_mcf_rx_check_opcode_pfc('1), + .cfg_mcf_rx_forward('0), + .cfg_mcf_rx_enable('0), + .cfg_tx_lfc_eth_dst('{2{48'h01_80_C2_00_00_01}}), + .cfg_tx_lfc_eth_src('{2{48'h80_23_31_43_54_4C}}), + .cfg_tx_lfc_eth_type('{2{16'h8808}}), + .cfg_tx_lfc_opcode('{2{16'h0001}}), + .cfg_tx_lfc_en('0), + .cfg_tx_lfc_quanta('{2{16'hffff}}), + .cfg_tx_lfc_refresh('{2{16'h7fff}}), + .cfg_tx_pfc_eth_dst('{2{48'h01_80_C2_00_00_01}}), + .cfg_tx_pfc_eth_src('{2{48'h80_23_31_43_54_4C}}), + .cfg_tx_pfc_eth_type('{2{16'h8808}}), + .cfg_tx_pfc_opcode('{2{16'h0101}}), + .cfg_tx_pfc_en('0), + .cfg_tx_pfc_quanta('{2{'{8{16'hffff}}}}), + .cfg_tx_pfc_refresh('{2{'{8{16'h7fff}}}}), + .cfg_rx_lfc_opcode('{2{16'h0001}}), + .cfg_rx_lfc_en('0), + .cfg_rx_pfc_opcode('{2{16'h0101}}), + .cfg_rx_pfc_en('0) + ); + + for (genvar n = 0; n < 2; n = n + 1) begin : sfp_ch + + taxi_axis_async_fifo #( + .DEPTH(16384), + .RAM_PIPELINE(2), + .FRAME_FIFO(1), + .USER_BAD_FRAME_VALUE(1'b1), + .USER_BAD_FRAME_MASK(1'b1), + .DROP_OVERSIZE_FRAME(1), + .DROP_BAD_FRAME(1), + .DROP_WHEN_FULL(1) + ) + ch_fifo ( + /* + * AXI4-Stream input (sink) + */ + .s_clk(sfp_rx_clk[n]), + .s_rst(sfp_rx_rst[n]), + .s_axis(axis_sfp_rx[n]), + + /* + * AXI4-Stream output (source) + */ + .m_clk(sfp_tx_clk[n]), + .m_rst(sfp_tx_rst[n]), + .m_axis(axis_sfp_tx[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 + +end endmodule diff --git a/example/KCU105/fpga/tb/fpga_core/Makefile b/example/KCU105/fpga/tb/fpga_core/Makefile index a9ae733..93bbefe 100644 --- a/example/KCU105/fpga/tb/fpga_core/Makefile +++ b/example/KCU105/fpga/tb/fpga_core/Makefile @@ -20,6 +20,7 @@ MODULE = $(COCOTB_TEST_MODULES) TOPLEVEL = $(COCOTB_TOPLEVEL) VERILOG_SOURCES += ../../rtl/$(DUT).sv VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f +VERILOG_SOURCES += ../../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us.f VERILOG_SOURCES += ../../lib/taxi/rtl/lss/taxi_uart.f VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_reset.sv VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_signal.sv @@ -32,7 +33,10 @@ uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) # module parameters -#export PARAM_A := value +export PARAM_SIM := "1'b1" +export PARAM_VENDOR := "\"XILINX\"" +export PARAM_FAMILY := "\"kintexu\"" +export PARAM_SFP_RATE := "1'b1" ifeq ($(SIM), icarus) PLUSARGS += -fst diff --git a/example/KCU105/fpga/tb/fpga_core/baser.py b/example/KCU105/fpga/tb/fpga_core/baser.py new file mode 120000 index 0000000..ac1737a --- /dev/null +++ b/example/KCU105/fpga/tb/fpga_core/baser.py @@ -0,0 +1 @@ +../../lib/taxi/tb/eth/baser.py \ No newline at end of file diff --git a/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py b/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py index 8ad6fc4..816324c 100644 --- a/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py +++ b/example/KCU105/fpga/tb/fpga_core/test_fpga_core.py @@ -11,7 +11,9 @@ Authors: import logging import os +import sys +import pytest import cocotb_test.simulator import cocotb @@ -20,8 +22,19 @@ from cocotb.clock import Clock from cocotb.triggers import RisingEdge, Combine from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink +from cocotbext.eth import XgmiiFrame from cocotbext.uart import UartSource, UartSink +try: + from baser import BaseRSerdesSource, BaseRSerdesSink +except ImportError: + # attempt import from current directory + sys.path.insert(0, os.path.join(os.path.dirname(__file__))) + try: + from baser import BaseRSerdesSource, BaseRSerdesSink + finally: + del sys.path[0] + class TB: def __init__(self, dut, speed=1000e6): @@ -32,23 +45,37 @@ class TB: cocotb.start_soon(Clock(dut.clk, 8, units="ns").start()) cocotb.start_soon(Clock(dut.phy_gmii_clk, 8, units="ns").start()) - cocotb.start_soon(Clock(dut.sfp0_gmii_clk, 8, units="ns").start()) - cocotb.start_soon(Clock(dut.sfp1_gmii_clk, 8, units="ns").start()) self.gmii_source = GmiiSource(dut.phy_gmii_rxd, dut.phy_gmii_rx_er, dut.phy_gmii_rx_dv, dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en) self.gmii_sink = GmiiSink(dut.phy_gmii_txd, dut.phy_gmii_tx_er, dut.phy_gmii_tx_en, dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en) - self.sfp0_source = GmiiSource(dut.sfp0_gmii_rxd, dut.sfp0_gmii_rx_er, dut.sfp0_gmii_rx_dv, - dut.sfp0_gmii_clk, dut.sfp0_gmii_rst, dut.sfp0_gmii_clk_en) - self.sfp0_sink = GmiiSink(dut.sfp0_gmii_txd, dut.sfp0_gmii_tx_er, dut.sfp0_gmii_tx_en, - dut.sfp0_gmii_clk, dut.sfp0_gmii_rst, dut.sfp0_gmii_clk_en) + self.sfp_sources = [] + self.sfp_sinks = [] - self.sfp1_source = GmiiSource(dut.sfp1_gmii_rxd, dut.sfp1_gmii_rx_er, dut.sfp1_gmii_rx_dv, - dut.sfp1_gmii_clk, dut.sfp1_gmii_rst, dut.sfp1_gmii_clk_en) - self.sfp1_sink = GmiiSink(dut.sfp1_gmii_txd, dut.sfp1_gmii_tx_er, dut.sfp1_gmii_tx_en, - dut.sfp1_gmii_clk, dut.sfp1_gmii_rst, dut.sfp1_gmii_clk_en) + if dut.SFP_RATE.value == 0: + cocotb.start_soon(Clock(dut.sfp0_gmii_clk, 8, units="ns").start()) + cocotb.start_soon(Clock(dut.sfp1_gmii_clk, 8, units="ns").start()) + + self.sfp_sources.append(GmiiSource(dut.sfp0_gmii_rxd, dut.sfp0_gmii_rx_er, dut.sfp0_gmii_rx_dv, + dut.sfp0_gmii_clk, dut.sfp0_gmii_rst, dut.sfp0_gmii_clk_en)) + self.sfp_sinks.append(GmiiSink(dut.sfp0_gmii_txd, dut.sfp0_gmii_tx_er, dut.sfp0_gmii_tx_en, + dut.sfp0_gmii_clk, dut.sfp0_gmii_rst, dut.sfp0_gmii_clk_en)) + + self.sfp_sources.append(GmiiSource(dut.sfp1_gmii_rxd, dut.sfp1_gmii_rx_er, dut.sfp1_gmii_rx_dv, + dut.sfp1_gmii_clk, dut.sfp1_gmii_rst, dut.sfp1_gmii_clk_en)) + self.sfp_sinks.append(GmiiSink(dut.sfp1_gmii_txd, dut.sfp1_gmii_tx_er, dut.sfp1_gmii_tx_en, + dut.sfp1_gmii_clk, dut.sfp1_gmii_rst, dut.sfp1_gmii_clk_en)) + else: + cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, units="ns").start()) + + for ch in dut.sfp_mac.sfp_mac_inst.ch: + cocotb.start_soon(Clock(ch.ch_inst.tx_clk, 6.4, units="ns").start()) + cocotb.start_soon(Clock(ch.ch_inst.rx_clk, 6.4, units="ns").start()) + + self.sfp_sources.append(BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)) + self.sfp_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.tx_clk, reverse=True)) self.uart_source = UartSource(dut.uart_rxd, baud=115200, bits=8, stop_bits=1) self.uart_sink = UartSink(dut.uart_txd, baud=115200, bits=8, stop_bits=1) @@ -86,6 +113,9 @@ class TB: self.dut.sfp0_gmii_rst.value = 0 self.dut.sfp1_gmii_rst.value = 0 + for k in range(10): + await RisingEdge(self.dut.clk) + async def uart_test(tb, source, sink): tb.log.info("Test UART") @@ -148,6 +178,46 @@ async def mac_test(tb, source, sink): tb.log.info("MAC test done") +async def mac_test_25g(tb, source, sink): + tb.log.info("Test MAC") + + tb.log.info("Multiple small packets") + + count = 64 + + pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)] + + for p in pkts: + await source.send(XgmiiFrame.from_payload(p)) + + for k in range(count): + rx_frame = await sink.recv() + + tb.log.info("RX frame: %s", rx_frame) + + assert rx_frame.get_payload() == pkts[k] + assert rx_frame.check_fcs() + + tb.log.info("Multiple large packets") + + count = 32 + + pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)] + + for p in pkts: + await source.send(XgmiiFrame.from_payload(p)) + + for k in range(count): + rx_frame = await sink.recv() + + tb.log.info("RX frame: %s", rx_frame) + + assert rx_frame.get_payload() == pkts[k] + assert rx_frame.check_fcs() + + tb.log.info("MAC test done") + + @cocotb.test() async def run_test(dut): @@ -155,23 +225,25 @@ async def run_test(dut): await tb.init() + tests = [] + tb.log.info("Start UART test") - uart_test_cr = cocotb.start_soon(uart_test(tb, tb.uart_source, tb.uart_sink)) + tests.append(cocotb.start_soon(uart_test(tb, tb.uart_source, tb.uart_sink))) tb.log.info("Start BASE-T MAC loopback test") - baset_test_cr = cocotb.start_soon(mac_test(tb, tb.gmii_source, tb.gmii_sink)) + tests.append(cocotb.start_soon(mac_test(tb, tb.gmii_source, tb.gmii_sink))) - tb.log.info("Start SFP0 MAC loopback test") + for k in range(len(tb.sfp_sources)): + if dut.SFP_RATE.value == 0: + tb.log.info("Start SFP %d 1G MAC loopback test", k) + tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_sources[k], tb.sfp_sinks[k]))) + else: + tb.log.info("Start SFP %d 10G MAC loopback test", k) + tests.append(cocotb.start_soon(mac_test_25g(tb, tb.sfp_sources[k], tb.sfp_sinks[k]))) - sfp0_test_cr = cocotb.start_soon(mac_test(tb, tb.sfp0_source, tb.sfp0_sink)) - - tb.log.info("Start SFP1 MAC loopback test") - - sfp1_test_cr = cocotb.start_soon(mac_test(tb, tb.sfp1_source, tb.sfp1_sink)) - - await Combine(uart_test_cr, baset_test_cr, sfp0_test_cr, sfp1_test_cr) + await Combine(*tests) await RisingEdge(dut.clk) await RisingEdge(dut.clk) @@ -197,7 +269,8 @@ def process_f_files(files): return list(lst.values()) -def test_fpga_core(request): +@pytest.mark.parametrize("sfp_rate", [0, 1]) +def test_fpga_core(request, sfp_rate): dut = "fpga_core" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut @@ -205,6 +278,7 @@ def test_fpga_core(request): verilog_sources = [ os.path.join(rtl_dir, f"{dut}.sv"), os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_fifo.f"), + os.path.join(lib_dir, "taxi", "rtl", "eth", "us", "taxi_eth_mac_25g_us.f"), os.path.join(lib_dir, "taxi", "rtl", "lss", "taxi_uart.f"), os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_reset.sv"), os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_signal.sv"), @@ -215,7 +289,10 @@ def test_fpga_core(request): parameters = {} - # parameters['A'] = val + parameters['SIM'] = "1'b1" + parameters['VENDOR'] = "\"XILINX\"" + parameters['FAMILY'] = "\"kintexu\"" + parameters['SFP_RATE'] = f"1'b{sfp_rate}" extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}