diff --git a/src/eth/example/XEM8320/fpga/fpga/Makefile b/src/eth/example/XEM8320/fpga/fpga_10g/Makefile similarity index 97% rename from src/eth/example/XEM8320/fpga/fpga/Makefile rename to src/eth/example/XEM8320/fpga/fpga_10g/Makefile index f18dd2d..40cbd6e 100644 --- a/src/eth/example/XEM8320/fpga/fpga/Makefile +++ b/src/eth/example/XEM8320/fpga/fpga_10g/Makefile @@ -36,7 +36,7 @@ XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl IP_TCL_FILES = $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gty_156.tcl # Configuration -#CONFIG_TCL_FILES = ./config.tcl +CONFIG_TCL_FILES = ./config.tcl include ../common/vivado.mk diff --git a/src/eth/example/XEM8320/fpga/fpga_10g/config.tcl b/src/eth/example/XEM8320/fpga/fpga_10g/config.tcl new file mode 100644 index 0000000..4359e24 --- /dev/null +++ b/src/eth/example/XEM8320/fpga/fpga_10g/config.tcl @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (c) 2025 FPGA Ninja, LLC +# +# Authors: +# - Alex Forencich +# + +set params [dict create] + +# MAC configuration +dict set params CFG_LOW_LATENCY "1" +dict set params COMBINED_MAC_PCS "1" +dict set params MAC_DATA_W "32" + +# apply parameters to top-level +set param_list {} +dict for {name value} $params { + lappend param_list $name=$value +} + +set_property generic $param_list [get_filesets sources_1] diff --git a/src/eth/example/XEM8320/fpga/fpga_1g/Makefile b/src/eth/example/XEM8320/fpga/fpga_1g/Makefile new file mode 100644 index 0000000..da1a521 --- /dev/null +++ b/src/eth/example/XEM8320/fpga/fpga_1g/Makefile @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (c) 2026 FPGA Ninja, LLC +# +# Authors: +# - Alex Forencich +# + +# FPGA settings +FPGA_PART = xcau25p-ffvb676-2-e +FPGA_TOP = fpga +FPGA_ARCH = artixuplus + +RTL_DIR = ../rtl +LIB_DIR = ../lib +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 += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_1g_basex_us.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 + +# XDC files +XDC_FILES += ../syn/fpga.xdc +XDC_FILES += ../syn/gpio.xdc +XDC_FILES += ../syn/sfp.xdc +XDC_FILES += $(TAXI_SRC_DIR)/eth/syn/vivado/taxi_eth_mac_fifo.tcl +XDC_FILES += $(TAXI_SRC_DIR)/axis/syn/vivado/taxi_axis_async_fifo.tcl +XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_reset.tcl +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_1g_basex_us_gty_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/src/eth/example/XEM8320/fpga/fpga_1g/config.tcl b/src/eth/example/XEM8320/fpga/fpga_1g/config.tcl new file mode 100644 index 0000000..ab45ff6 --- /dev/null +++ b/src/eth/example/XEM8320/fpga/fpga_1g/config.tcl @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: MIT +# +# Copyright (c) 2025 FPGA Ninja, LLC +# +# Authors: +# - Alex Forencich +# + +set params [dict create] + +# MAC configuration +dict set params CFG_LOW_LATENCY "1" +dict set params COMBINED_MAC_PCS "1" +dict set params MAC_DATA_W "16" + +# apply parameters to top-level +set param_list {} +dict for {name value} $params { + lappend param_list $name=$value +} + +set_property generic $param_list [get_filesets sources_1] diff --git a/src/eth/example/XEM8320/fpga/rtl/fpga.sv b/src/eth/example/XEM8320/fpga/rtl/fpga.sv index d0c1a74..6fcdb03 100644 --- a/src/eth/example/XEM8320/fpga/rtl/fpga.sv +++ b/src/eth/example/XEM8320/fpga/rtl/fpga.sv @@ -22,7 +22,11 @@ module fpga # // vendor ("GENERIC", "XILINX", "ALTERA") parameter string VENDOR = "XILINX", // device family - parameter string FAMILY = "artixuplus" + parameter string FAMILY = "artixuplus", + // MAC configuration + parameter logic CFG_LOW_LATENCY = 1'b1, + parameter logic COMBINED_MAC_PCS = 1'b1, + parameter MAC_DATA_W = 32 ) ( /* @@ -189,7 +193,10 @@ sync_reset_125mhz_inst ( fpga_core #( .SIM(SIM), .VENDOR(VENDOR), - .FAMILY(FAMILY) + .FAMILY(FAMILY), + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), + .COMBINED_MAC_PCS(COMBINED_MAC_PCS), + .MAC_DATA_W(MAC_DATA_W) ) core_inst ( /* diff --git a/src/eth/example/XEM8320/fpga/rtl/fpga_core.sv b/src/eth/example/XEM8320/fpga/rtl/fpga_core.sv index e95e3ee..4f683cc 100644 --- a/src/eth/example/XEM8320/fpga/rtl/fpga_core.sv +++ b/src/eth/example/XEM8320/fpga/rtl/fpga_core.sv @@ -22,7 +22,11 @@ module fpga_core # // vendor ("GENERIC", "XILINX", "ALTERA") parameter string VENDOR = "XILINX", // device family - parameter string FAMILY = "artixuplus" + parameter string FAMILY = "artixuplus", + // MAC configuration + parameter logic CFG_LOW_LATENCY = 1'b1, + parameter logic COMBINED_MAC_PCS = 1'b1, + parameter MAC_DATA_W = 32 ) ( /* @@ -84,10 +88,10 @@ wire sfp_mgt_refclk_2_bufg; wire sfp_rst; -taxi_axis_if #(.DATA_W(32), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_tx[2](); +taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_tx[2](); taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[2](); -taxi_axis_if #(.DATA_W(32), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_rx[2](); -taxi_axis_if #(.DATA_W(16), .KEEP_W(1), .KEEP_EN(0), .LAST_EN(0), .USER_EN(1), .USER_W(1), .ID_EN(1), .ID_W(8)) axis_sfp_stat(); +taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_rx[2](); +taxi_axis_if #(.DATA_W(16), .KEEP_W(1), .KEEP_EN(0), .LAST_EN(0), .USER_EN(1), .USER_W(1), .ID_EN(1), .ID_W(8)) axis_eth_stat(); if (SIM) begin @@ -132,261 +136,527 @@ taxi_apb_if #( ) gt_apb_ctrl(); -taxi_eth_mac_25g_us #( - .SIM(SIM), - .VENDOR(VENDOR), - .FAMILY(FAMILY), +if (MAC_DATA_W == 16) begin : sfp_mac - .CNT(2), + taxi_eth_mac_1g_basex_us #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), - // GT config - .CFG_LOW_LATENCY(1), + .CNT(2), - // GT type - .GT_TYPE("GTY"), + // GT config + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), - // PHY parameters - .DATA_W(axis_sfp_tx[0].DATA_W), - .USXGMII_EN(1'b1), - .DIC_EN(1'b1), - .PTP_TS_EN(1'b0), - .PTP_TD_EN(1'b0), - .PTP_TS_FMT_TOD(1'b1), - .PTP_TS_W(96), - .PTP_TD_SDI_PIPELINE(2), - .PRBS31_EN(1'b0), - .TX_SERDES_PIPELINE(1), - .RX_SERDES_PIPELINE(1), - .COUNT_125US(125000/6.4), - .STAT_EN(1'b0) -) -sfp_mac_inst ( - .xcvr_ctrl_clk(clk_125mhz), - .xcvr_ctrl_rst(sfp_rst), + // GT type + .GT_TYPE("GTY"), - /* - * Transceiver control - */ - .s_apb_ctrl(gt_apb_ctrl), + // PHY parameters + .COMBINED_MAC_PCS(COMBINED_MAC_PCS), + .SGMII_EN(1'b1), + .AN_EN(1'b1), + .DIC_EN(1'b1), + .PTP_TS_EN(1'b0), + .PTP_TD_EN(1'b0), + .PTP_TS_FMT_TOD(1'b1), + .PTP_TS_W(96), + .PTP_TD_SDI_PIPELINE(2), + .PRBS31_EN(1'b0), + .TX_SERDES_PIPELINE(1), + .RX_SERDES_PIPELINE(1), + .COUNT_125US(125000/6.4), + .STAT_EN(1'b0) + ) + sfp_mac_inst ( + .xcvr_ctrl_clk(clk_125mhz), + .xcvr_ctrl_rst(sfp_rst), - /* - * Common - */ - .xcvr_gtpowergood_out(sfp_gtpowergood), - .xcvr_gtrefclk00_in(sfp_mgt_refclk_2), - .xcvr_qpll0pd_in(1'b0), - .xcvr_qpll0reset_in(1'b0), - .xcvr_qpll0pcierate_in(3'd0), - .xcvr_qpll0lock_out(), - .xcvr_qpll0clk_out(), - .xcvr_qpll0refclk_out(), - .xcvr_gtrefclk01_in(sfp_mgt_refclk_2), - .xcvr_qpll1pd_in(1'b0), - .xcvr_qpll1reset_in(1'b0), - .xcvr_qpll1pcierate_in(3'd0), - .xcvr_qpll1lock_out(), - .xcvr_qpll1clk_out(), - .xcvr_qpll1refclk_out(), + /* + * Transceiver control + */ + .s_apb_ctrl(gt_apb_ctrl), - /* - * Serial data - */ - .xcvr_txp(sfp_tx_p), - .xcvr_txn(sfp_tx_n), - .xcvr_rxp(sfp_rx_p), - .xcvr_rxn(sfp_rx_n), + /* + * Common + */ + .xcvr_gtpowergood_out(sfp_gtpowergood), + .xcvr_gtrefclk00_in(sfp_mgt_refclk_2), + .xcvr_qpll0pd_in(1'b0), + .xcvr_qpll0reset_in(1'b0), + .xcvr_qpll0pcierate_in(3'd0), + .xcvr_qpll0lock_out(), + .xcvr_qpll0clk_out(), + .xcvr_qpll0refclk_out(), + .xcvr_gtrefclk01_in(sfp_mgt_refclk_2), + .xcvr_qpll1pd_in(1'b0), + .xcvr_qpll1reset_in(1'b0), + .xcvr_qpll1pcierate_in(3'd0), + .xcvr_qpll1lock_out(), + .xcvr_qpll1clk_out(), + .xcvr_qpll1refclk_out(), - /* - * MAC clocks - */ - .rx_clk(sfp_rx_clk), - .rx_rst_in('{2{1'b0}}), - .rx_rst_out(sfp_rx_rst), - .tx_clk(sfp_tx_clk), - .tx_rst_in('{2{1'b0}}), - .tx_rst_out(sfp_tx_rst), + /* + * Serial data + */ + .xcvr_txp(sfp_tx_p), + .xcvr_txn(sfp_tx_n), + .xcvr_rxp(sfp_rx_p), + .xcvr_rxn(sfp_rx_n), - /* - * Transmit interface (AXI stream) - */ - .s_axis_tx(axis_sfp_tx), - .m_axis_tx_cpl(axis_sfp_tx_cpl), + /* + * MAC clocks + */ + .rx_clk(sfp_rx_clk), + .rx_rst_in('{2{1'b0}}), + .rx_rst_out(sfp_rx_rst), + .tx_clk(sfp_tx_clk), + .tx_rst_in('{2{1'b0}}), + .tx_rst_out(sfp_tx_rst), - /* - * Receive interface (AXI stream) - */ - .m_axis_rx(axis_sfp_rx), + /* + * Transmit interface (AXI stream) + */ + .s_axis_tx(axis_sfp_tx), + .m_axis_tx_cpl(axis_sfp_tx_cpl), - /* - * USXGMII autonegotiation - */ - .an_en('{2{1'b1}}), - .an_restart('{2{1'b0}}), - .an_speedup('{2{1'b0}}), - .an_timeout_en('{2{1'b1}}), - .an_usxgmii_en('{2{1'b0}}), - .an_usxgmii_auto('{2{1'b1}}), - .an_intr(), - .an_running(), - .an_complete(), - .an_timeout(), - .an_usxgmii_mode(), - .an_adv_ability_usxgmii('{2{16'h1601}}), - .an_lp_adv_ability(), - .an_lp_usxgmii_link(), - .an_lp_usxgmii_speed(), - .an_res_full_duplex(), + /* + * Receive interface (AXI stream) + */ + .m_axis_rx(axis_sfp_rx), - /* - * PTP clock - */ - .ptp_clk(1'b0), - .ptp_rst(1'b0), - .ptp_sample_clk(1'b0), - .ptp_td_sdi(1'b0), - .tx_ptp_ts_in('{2{'0}}), - .tx_ptp_ts_out(), - .tx_ptp_ts_step_out(), - .tx_ptp_locked(), - .rx_ptp_ts_in('{2{'0}}), - .rx_ptp_ts_out(), - .rx_ptp_ts_step_out(), - .rx_ptp_locked(), + /* + * Autonegotiation + */ + .an_en('{2{1'b1}}), + .an_restart('{2{1'b0}}), + .an_speedup('{2{1'b0}}), + .an_timeout_en('{2{1'b1}}), + .an_sgmii_en('{2{1'b0}}), + .an_sgmii_auto('{2{1'b1}}), + .an_intr(), + .an_running(), + .an_complete(), + .an_timeout(), + .an_sgmii_mode(), + .an_adv_ability_basex('{2{16'h0020}}), + .an_adv_ability_sgmii('{2{16'h0001}}), + .an_lp_adv_ability(), + .an_lp_remote_fault(), + .an_lp_sgmii_link(), + .an_lp_sgmii_speed(), + .an_res_full_duplex(), + .an_res_tx_pause(), + .an_res_rx_pause(), - /* - * Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE) - */ - .tx_lfc_req('{2{1'b0}}), - .tx_lfc_resend('{2{1'b0}}), - .rx_lfc_en('{2{1'b0}}), - .rx_lfc_req(), - .rx_lfc_ack('{2{1'b0}}), + /* + * PTP clock + */ + .ptp_clk(1'b0), + .ptp_rst(1'b0), + .ptp_sample_clk(1'b0), + .ptp_td_sdi(1'b0), + .tx_ptp_ts_in('{2{'0}}), + .tx_ptp_ts_out(), + .tx_ptp_ts_step_out(), + .tx_ptp_locked(), + .rx_ptp_ts_in('{2{'0}}), + .rx_ptp_ts_out(), + .rx_ptp_ts_step_out(), + .rx_ptp_locked(), - /* - * Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC) - */ - .tx_pfc_req('{2{'0}}), - .tx_pfc_resend('{2{1'b0}}), - .rx_pfc_en('{2{'0}}), - .rx_pfc_req(), - .rx_pfc_ack('{2{'0}}), + /* + * Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE) + */ + .tx_lfc_req('{2{1'b0}}), + .tx_lfc_resend('{2{1'b0}}), + .rx_lfc_en('{2{1'b0}}), + .rx_lfc_req(), + .rx_lfc_ack('{2{1'b0}}), - /* - * Pause interface - */ - .tx_lfc_pause_en('{2{1'b0}}), - .tx_pause_req('{2{1'b0}}), - .tx_pause_ack(), + /* + * Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC) + */ + .tx_pfc_req('{2{'0}}), + .tx_pfc_resend('{2{1'b0}}), + .rx_pfc_en('{2{'0}}), + .rx_pfc_req(), + .rx_pfc_ack('{2{'0}}), - /* - * Statistics - */ - .stat_clk(clk_125mhz), - .stat_rst(rst_125mhz), - .m_axis_stat(axis_sfp_stat), + /* + * Pause interface + */ + .tx_lfc_pause_en('{2{1'b0}}), + .tx_pause_req('{2{1'b0}}), + .tx_pause_ack(), - /* - * Status - */ - .tx_start_packet(), - .stat_tx_byte(), - .stat_tx_pkt_len(), - .stat_tx_pkt_ucast(), - .stat_tx_pkt_mcast(), - .stat_tx_pkt_bcast(), - .stat_tx_pkt_vlan(), - .stat_tx_pkt_good(), - .stat_tx_pkt_bad(), - .stat_tx_pad_frame(), - .stat_tx_err_oversize(), - .stat_tx_err_user(), - .stat_tx_err_underflow(), - .rx_start_packet(), - .rx_error_count(), - .rx_block_lock(), - .rx_high_ber(), - .rx_status(sfp_rx_status), - .stat_rx_byte(), - .stat_rx_pkt_len(), - .stat_rx_pkt_fragment(), - .stat_rx_pkt_jabber(), - .stat_rx_pkt_ucast(), - .stat_rx_pkt_mcast(), - .stat_rx_pkt_bcast(), - .stat_rx_pkt_vlan(), - .stat_rx_pkt_good(), - .stat_rx_pkt_bad(), - .stat_rx_err_oversize(), - .stat_rx_err_bad_fcs(), - .stat_rx_err_bad_block(), - .stat_rx_err_framing(), - .stat_rx_err_preamble(), - .stat_rx_fifo_drop('{2{1'b0}}), - .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(), + /* + * Statistics + */ + .stat_clk(clk_125mhz), + .stat_rst(rst_125mhz), + .m_axis_stat(axis_eth_stat), - /* - * Configuration - */ - .cfg_tx_pad_en('{2{1'b1}}), - .cfg_tx_min_pkt_len('{2{8'd60-1}}), - .cfg_tx_max_pkt_len('{2{16'd9218-1}}), - .cfg_tx_ifg('{2{8'd12}}), - .cfg_tx_enable('{2{1'b1}}), - .cfg_rx_max_pkt_len('{2{16'd9218-1}}), - .cfg_rx_enable('{2{1'b1}}), - .cfg_tx_prbs31_enable('{2{1'b0}}), - .cfg_rx_prbs31_enable('{2{1'b0}}), - .cfg_mcf_rx_eth_dst_mcast('{2{48'h01_80_C2_00_00_01}}), - .cfg_mcf_rx_check_eth_dst_mcast('{2{1'b1}}), - .cfg_mcf_rx_eth_dst_ucast('{2{48'd0}}), - .cfg_mcf_rx_check_eth_dst_ucast('{2{1'b0}}), - .cfg_mcf_rx_eth_src('{2{48'd0}}), - .cfg_mcf_rx_check_eth_src('{2{1'b0}}), - .cfg_mcf_rx_eth_type('{2{16'h8808}}), - .cfg_mcf_rx_opcode_lfc('{2{16'h0001}}), - .cfg_mcf_rx_check_opcode_lfc('{2{1'b1}}), - .cfg_mcf_rx_opcode_pfc('{2{16'h0101}}), - .cfg_mcf_rx_check_opcode_pfc('{2{1'b1}}), - .cfg_mcf_rx_forward('{2{1'b0}}), - .cfg_mcf_rx_enable('{2{1'b0}}), - .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('{2{1'b0}}), - .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('{2{1'b0}}), - .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('{2{1'b0}}), - .cfg_rx_pfc_opcode('{2{16'h0101}}), - .cfg_rx_pfc_en('{2{1'b0}}) -); + /* + * Status + */ + .tx_start_packet(), + .stat_tx_byte(), + .stat_tx_pkt_len(), + .stat_tx_pkt_ucast(), + .stat_tx_pkt_mcast(), + .stat_tx_pkt_bcast(), + .stat_tx_pkt_vlan(), + .stat_tx_pkt_good(), + .stat_tx_pkt_bad(), + .stat_tx_pad_frame(), + .stat_tx_err_oversize(), + .stat_tx_err_user(), + .stat_tx_err_underflow(), + .rx_start_packet(), + .rx_error_count(), + .rx_block_lock(), + .rx_high_ber(), + .rx_status(sfp_rx_status), + .stat_rx_byte(), + .stat_rx_pkt_len(), + .stat_rx_pkt_fragment(), + .stat_rx_pkt_jabber(), + .stat_rx_pkt_ucast(), + .stat_rx_pkt_mcast(), + .stat_rx_pkt_bcast(), + .stat_rx_pkt_vlan(), + .stat_rx_pkt_good(), + .stat_rx_pkt_bad(), + .stat_rx_err_oversize(), + .stat_rx_err_bad_fcs(), + .stat_rx_err_bad_block(), + .stat_rx_err_framing(), + .stat_rx_err_preamble(), + .stat_rx_fifo_drop('{2{1'b0}}), + .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(), -for (genvar n = 0; n < 2; n = n + 1) begin : sfp_ch + /* + * Configuration + */ + .cfg_tx_pad_en('{2{1'b1}}), + .cfg_tx_min_pkt_len('{2{8'd60-1}}), + .cfg_tx_max_pkt_len('{2{16'd9218-1}}), + .cfg_tx_ifg('{2{8'd12}}), + .cfg_tx_enable('{2{1'b1}}), + .cfg_rx_max_pkt_len('{2{16'd9218-1}}), + .cfg_rx_enable('{2{1'b1}}), + .cfg_tx_prbs31_enable('{2{1'b0}}), + .cfg_rx_prbs31_enable('{2{1'b0}}), + .cfg_mcf_rx_eth_dst_mcast('{2{48'h01_80_C2_00_00_01}}), + .cfg_mcf_rx_check_eth_dst_mcast('{2{1'b1}}), + .cfg_mcf_rx_eth_dst_ucast('{2{48'd0}}), + .cfg_mcf_rx_check_eth_dst_ucast('{2{1'b0}}), + .cfg_mcf_rx_eth_src('{2{48'd0}}), + .cfg_mcf_rx_check_eth_src('{2{1'b0}}), + .cfg_mcf_rx_eth_type('{2{16'h8808}}), + .cfg_mcf_rx_opcode_lfc('{2{16'h0001}}), + .cfg_mcf_rx_check_opcode_lfc('{2{1'b1}}), + .cfg_mcf_rx_opcode_pfc('{2{16'h0101}}), + .cfg_mcf_rx_check_opcode_pfc('{2{1'b1}}), + .cfg_mcf_rx_forward('{2{1'b0}}), + .cfg_mcf_rx_enable('{2{1'b0}}), + .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('{2{1'b0}}), + .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('{2{1'b0}}), + .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('{2{1'b0}}), + .cfg_rx_pfc_opcode('{2{16'h0101}}), + .cfg_rx_pfc_en('{2{1'b0}}) + ); + +end else begin : sfp_mac + + taxi_eth_mac_25g_us #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + + .CNT(2), + + // GT config + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), + + // GT type + .GT_TYPE("GTY"), + + // PHY parameters + .COMBINED_MAC_PCS(COMBINED_MAC_PCS), + .DATA_W(axis_sfp_tx[0].DATA_W), + .USXGMII_EN(COMBINED_MAC_PCS), + .DIC_EN(1'b1), + .PTP_TS_EN(1'b0), + .PTP_TD_EN(1'b0), + .PTP_TS_FMT_TOD(1'b1), + .PTP_TS_W(96), + .PTP_TD_SDI_PIPELINE(2), + .PRBS31_EN(1'b0), + .TX_SERDES_PIPELINE(1), + .RX_SERDES_PIPELINE(1), + .COUNT_125US(125000/6.4), + .STAT_EN(1'b0) + ) + sfp_mac_inst ( + .xcvr_ctrl_clk(clk_125mhz), + .xcvr_ctrl_rst(sfp_rst), + + /* + * Transceiver control + */ + .s_apb_ctrl(gt_apb_ctrl), + + /* + * Common + */ + .xcvr_gtpowergood_out(sfp_gtpowergood), + .xcvr_gtrefclk00_in(sfp_mgt_refclk_2), + .xcvr_qpll0pd_in(1'b0), + .xcvr_qpll0reset_in(1'b0), + .xcvr_qpll0pcierate_in(3'd0), + .xcvr_qpll0lock_out(), + .xcvr_qpll0clk_out(), + .xcvr_qpll0refclk_out(), + .xcvr_gtrefclk01_in(sfp_mgt_refclk_2), + .xcvr_qpll1pd_in(1'b0), + .xcvr_qpll1reset_in(1'b0), + .xcvr_qpll1pcierate_in(3'd0), + .xcvr_qpll1lock_out(), + .xcvr_qpll1clk_out(), + .xcvr_qpll1refclk_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('{2{1'b0}}), + .rx_rst_out(sfp_rx_rst), + .tx_clk(sfp_tx_clk), + .tx_rst_in('{2{1'b0}}), + .tx_rst_out(sfp_tx_rst), + + /* + * 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), + + /* + * USXGMII autonegotiation + */ + .an_en('{2{1'b1}}), + .an_restart('{2{1'b0}}), + .an_speedup('{2{1'b0}}), + .an_timeout_en('{2{1'b1}}), + .an_usxgmii_en('{2{1'b0}}), + .an_usxgmii_auto('{2{1'b1}}), + .an_intr(), + .an_running(), + .an_complete(), + .an_timeout(), + .an_usxgmii_mode(), + .an_adv_ability_usxgmii('{2{16'h1601}}), + .an_lp_adv_ability(), + .an_lp_usxgmii_link(), + .an_lp_usxgmii_speed(), + .an_res_full_duplex(), + + /* + * PTP clock + */ + .ptp_clk(1'b0), + .ptp_rst(1'b0), + .ptp_sample_clk(1'b0), + .ptp_td_sdi(1'b0), + .tx_ptp_ts_in('{2{'0}}), + .tx_ptp_ts_out(), + .tx_ptp_ts_step_out(), + .tx_ptp_locked(), + .rx_ptp_ts_in('{2{'0}}), + .rx_ptp_ts_out(), + .rx_ptp_ts_step_out(), + .rx_ptp_locked(), + + /* + * Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE) + */ + .tx_lfc_req('{2{1'b0}}), + .tx_lfc_resend('{2{1'b0}}), + .rx_lfc_en('{2{1'b0}}), + .rx_lfc_req(), + .rx_lfc_ack('{2{1'b0}}), + + /* + * Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC) + */ + .tx_pfc_req('{2{'0}}), + .tx_pfc_resend('{2{1'b0}}), + .rx_pfc_en('{2{'0}}), + .rx_pfc_req(), + .rx_pfc_ack('{2{'0}}), + + /* + * Pause interface + */ + .tx_lfc_pause_en('{2{1'b0}}), + .tx_pause_req('{2{1'b0}}), + .tx_pause_ack(), + + /* + * Statistics + */ + .stat_clk(clk_125mhz), + .stat_rst(rst_125mhz), + .m_axis_stat(axis_eth_stat), + + /* + * Status + */ + .tx_start_packet(), + .stat_tx_byte(), + .stat_tx_pkt_len(), + .stat_tx_pkt_ucast(), + .stat_tx_pkt_mcast(), + .stat_tx_pkt_bcast(), + .stat_tx_pkt_vlan(), + .stat_tx_pkt_good(), + .stat_tx_pkt_bad(), + .stat_tx_pad_frame(), + .stat_tx_err_oversize(), + .stat_tx_err_user(), + .stat_tx_err_underflow(), + .rx_start_packet(), + .rx_error_count(), + .rx_block_lock(), + .rx_high_ber(), + .rx_status(sfp_rx_status), + .stat_rx_byte(), + .stat_rx_pkt_len(), + .stat_rx_pkt_fragment(), + .stat_rx_pkt_jabber(), + .stat_rx_pkt_ucast(), + .stat_rx_pkt_mcast(), + .stat_rx_pkt_bcast(), + .stat_rx_pkt_vlan(), + .stat_rx_pkt_good(), + .stat_rx_pkt_bad(), + .stat_rx_err_oversize(), + .stat_rx_err_bad_fcs(), + .stat_rx_err_bad_block(), + .stat_rx_err_framing(), + .stat_rx_err_preamble(), + .stat_rx_fifo_drop('{2{1'b0}}), + .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_tx_pad_en('{2{1'b1}}), + .cfg_tx_min_pkt_len('{2{8'd60-1}}), + .cfg_tx_max_pkt_len('{2{16'd9218-1}}), + .cfg_tx_ifg('{2{8'd12}}), + .cfg_tx_enable('{2{1'b1}}), + .cfg_rx_max_pkt_len('{2{16'd9218-1}}), + .cfg_rx_enable('{2{1'b1}}), + .cfg_tx_prbs31_enable('{2{1'b0}}), + .cfg_rx_prbs31_enable('{2{1'b0}}), + .cfg_mcf_rx_eth_dst_mcast('{2{48'h01_80_C2_00_00_01}}), + .cfg_mcf_rx_check_eth_dst_mcast('{2{1'b1}}), + .cfg_mcf_rx_eth_dst_ucast('{2{48'd0}}), + .cfg_mcf_rx_check_eth_dst_ucast('{2{1'b0}}), + .cfg_mcf_rx_eth_src('{2{48'd0}}), + .cfg_mcf_rx_check_eth_src('{2{1'b0}}), + .cfg_mcf_rx_eth_type('{2{16'h8808}}), + .cfg_mcf_rx_opcode_lfc('{2{16'h0001}}), + .cfg_mcf_rx_check_opcode_lfc('{2{1'b1}}), + .cfg_mcf_rx_opcode_pfc('{2{16'h0101}}), + .cfg_mcf_rx_check_opcode_pfc('{2{1'b1}}), + .cfg_mcf_rx_forward('{2{1'b0}}), + .cfg_mcf_rx_enable('{2{1'b0}}), + .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('{2{1'b0}}), + .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('{2{1'b0}}), + .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('{2{1'b0}}), + .cfg_rx_pfc_opcode('{2{16'h0101}}), + .cfg_rx_pfc_en('{2{1'b0}}) + ); + +end + +for (genvar n = 0; n < $size(axis_sfp_tx); n = n + 1) begin : sfp_ch taxi_axis_async_fifo #( .DEPTH(16384), diff --git a/src/eth/example/XEM8320/fpga/tb/fpga_core/Makefile b/src/eth/example/XEM8320/fpga/tb/fpga_core/Makefile index 3b082ec..c850d18 100644 --- a/src/eth/example/XEM8320/fpga/tb/fpga_core/Makefile +++ b/src/eth/example/XEM8320/fpga/tb/fpga_core/Makefile @@ -24,6 +24,7 @@ MODULE = $(COCOTB_TEST_MODULES) TOPLEVEL = $(COCOTB_TOPLEVEL) 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)/eth/rtl/us/taxi_eth_mac_1g_basex_us.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 @@ -38,6 +39,9 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) export PARAM_SIM := "1'b1" export PARAM_VENDOR := "\"XILINX\"" export PARAM_FAMILY := "\"artixuplus\"" +export PARAM_CFG_LOW_LATENCY := "1'b1" +export PARAM_COMBINED_MAC_PCS := "1'b1" +export PARAM_MAC_DATA_W := "32" ifeq ($(SIM), icarus) PLUSARGS += -fst diff --git a/src/eth/example/XEM8320/fpga/tb/fpga_core/basex.py b/src/eth/example/XEM8320/fpga/tb/fpga_core/basex.py new file mode 120000 index 0000000..b976cc4 --- /dev/null +++ b/src/eth/example/XEM8320/fpga/tb/fpga_core/basex.py @@ -0,0 +1 @@ +../../lib/taxi/src/eth/tb/basex.py \ No newline at end of file diff --git a/src/eth/example/XEM8320/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/XEM8320/fpga/tb/fpga_core/test_fpga_core.py index cbdcd1c..6c8a6c2 100644 --- a/src/eth/example/XEM8320/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/XEM8320/fpga/tb/fpga_core/test_fpga_core.py @@ -26,11 +26,13 @@ from cocotbext.uart import UartSource, UartSink try: from baser import BaseRSerdesSource, BaseRSerdesSink + from basex import BaseXSerdesSource, BaseXSerdesSink except ImportError: # attempt import from current directory sys.path.insert(0, os.path.join(os.path.dirname(__file__))) try: from baser import BaseRSerdesSource, BaseRSerdesSink + from basex import BaseXSerdesSource, BaseXSerdesSink finally: del sys.path[0] @@ -49,39 +51,77 @@ class TB: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_2_p, 6.4, units="ns").start()) - for ch in dut.sfp_mac_inst.ch: + for ch in dut.sfp_mac.sfp_mac_inst.ch: gt_inst = ch.ch_inst.gt.gt_inst - if ch.ch_inst.CFG_LOW_LATENCY.value: - clk = 3.102 - gbx_cfg = (66, [64, 65]) + if dut.MAC_DATA_W.value == 16: + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 16 + gbx_cfg = None + else: + clk = 16 + gbx_cfg = None + + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + + self.sfp_sources.append(BaseXSerdesSource( + data=gt_inst.serdes_rx_data, + data_k=gt_inst.serdes_rx_data_k, + data_valid=gt_inst.serdes_rx_data_valid, + clock=gt_inst.rx_clk, + enc_8b10b=False, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseXSerdesSink( + data=gt_inst.serdes_tx_data, + data_k=gt_inst.serdes_tx_data_k, + data_valid=gt_inst.serdes_tx_data_valid, + gbx_sync=gt_inst.serdes_tx_gbx_sync, + clock=gt_inst.tx_clk, + dec_8b10b=False, + gbx_cfg=gbx_cfg + )) + else: - clk = 3.2 - gbx_cfg = None + if ch.ch_inst.DATA_W.value == 64: + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 6.206 + gbx_cfg = (66, [64, 65]) + else: + clk = 6.4 + gbx_cfg = None + else: + if ch.ch_inst.CFG_LOW_LATENCY.value: + clk = 3.102 + gbx_cfg = (66, [64, 65]) + else: + clk = 3.2 + gbx_cfg = None - cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) - cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.tx_clk, clk, units="ns").start()) + cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) - self.sfp_sources.append(BaseRSerdesSource( - data=gt_inst.serdes_rx_data, - data_valid=gt_inst.serdes_rx_data_valid, - hdr=gt_inst.serdes_rx_hdr, - hdr_valid=gt_inst.serdes_rx_hdr_valid, - clock=gt_inst.rx_clk, - slip=gt_inst.serdes_rx_bitslip, - reverse=True, - gbx_cfg=gbx_cfg - )) - self.sfp_sinks.append(BaseRSerdesSink( - data=gt_inst.serdes_tx_data, - data_valid=gt_inst.serdes_tx_data_valid, - hdr=gt_inst.serdes_tx_hdr, - hdr_valid=gt_inst.serdes_tx_hdr_valid, - gbx_sync=gt_inst.serdes_tx_gbx_sync, - clock=gt_inst.tx_clk, - reverse=True, - gbx_cfg=gbx_cfg - )) + self.sfp_sources.append(BaseRSerdesSource( + data=gt_inst.serdes_rx_data, + data_valid=gt_inst.serdes_rx_data_valid, + hdr=gt_inst.serdes_rx_hdr, + hdr_valid=gt_inst.serdes_rx_hdr_valid, + clock=gt_inst.rx_clk, + slip=gt_inst.serdes_rx_bitslip, + reverse=True, + gbx_cfg=gbx_cfg + )) + self.sfp_sinks.append(BaseRSerdesSink( + data=gt_inst.serdes_tx_data, + data_valid=gt_inst.serdes_tx_data_valid, + hdr=gt_inst.serdes_tx_hdr, + hdr_valid=gt_inst.serdes_tx_hdr_valid, + gbx_sync=gt_inst.serdes_tx_gbx_sync, + clock=gt_inst.tx_clk, + reverse=True, + gbx_cfg=gbx_cfg + )) async def init(self): @@ -101,12 +141,10 @@ class TB: await RisingEdge(self.dut.clk_125mhz) -async def mac_test_10g(tb, source, sink): +async def mac_test(tb, source, sink): tb.log.info("Test MAC") - tb.log.info("Wait for block lock") - for k in range(1200): - await RisingEdge(tb.dut.clk_125mhz) + sink.clear() tb.log.info("Multiple small packets") @@ -154,9 +192,13 @@ async def run_test(dut): tests = [] + tb.log.info("Wait for block lock") + for k in range(1200): + await RisingEdge(dut.clk_125mhz) + for k in range(len(tb.sfp_sources)): - tb.log.info("Start SFP %d 10G MAC loopback test", k) - tests.append(cocotb.start_soon(mac_test_10g(tb, tb.sfp_sources[k], tb.sfp_sinks[k]))) + tb.log.info("Start SFP %d MAC loopback test", k) + tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_sources[k], tb.sfp_sinks[k]))) await Combine(*tests) @@ -185,7 +227,8 @@ def process_f_files(files): return list(lst.values()) -def test_fpga_core(request): +@pytest.mark.parametrize("mac_data_w", [16, 32, 64]) +def test_fpga_core(request, mac_data_w): dut = "fpga_core" module = os.path.splitext(os.path.basename(__file__))[0] toplevel = dut @@ -193,6 +236,7 @@ def test_fpga_core(request): verilog_sources = [ 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, "eth", "rtl", "us", "taxi_eth_mac_1g_basex_us.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"), @@ -205,6 +249,9 @@ def test_fpga_core(request): parameters['SIM'] = "1'b1" parameters['VENDOR'] = "\"XILINX\"" parameters['FAMILY'] = "\"artixuplus\"" + parameters['CFG_LOW_LATENCY'] = "1'b1" + parameters['COMBINED_MAC_PCS'] = "1'b1" + parameters['MAC_DATA_W'] = mac_data_w extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}