From 511b65e4a548e0320735802ef01db97ff8a207f5 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sat, 8 Aug 2026 22:15:35 -0700 Subject: [PATCH] eth: Update KR260 1000BASE-X example design implementation Signed-off-by: Alex Forencich --- src/eth/example/KR260/fpga/fpga_10g/Makefile | 2 +- .../example/KR260/fpga/fpga_10g/config.tcl | 7 +- src/eth/example/KR260/fpga/fpga_1g/Makefile | 4 +- src/eth/example/KR260/fpga/fpga_1g/config.tcl | 7 +- .../example/KR260/fpga/ip/basex_pcs_pma_0.tcl | 21 - src/eth/example/KR260/fpga/rtl/fpga.sv | 118 +---- src/eth/example/KR260/fpga/rtl/fpga_core.sv | 438 ++++++++++++------ .../example/KR260/fpga/tb/fpga_core/Makefile | 6 +- .../example/KR260/fpga/tb/fpga_core/basex.py | 1 + .../KR260/fpga/tb/fpga_core/test_fpga_core.py | 180 ++++--- 10 files changed, 416 insertions(+), 368 deletions(-) delete mode 100644 src/eth/example/KR260/fpga/ip/basex_pcs_pma_0.tcl create mode 120000 src/eth/example/KR260/fpga/tb/fpga_core/basex.py diff --git a/src/eth/example/KR260/fpga/fpga_10g/Makefile b/src/eth/example/KR260/fpga/fpga_10g/Makefile index 4b5fc9b..90c01d3 100644 --- a/src/eth/example/KR260/fpga/fpga_10g/Makefile +++ b/src/eth/example/KR260/fpga/fpga_10g/Makefile @@ -37,7 +37,7 @@ 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_10g_us_gth_156.tcl +IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_10g_us_gth_156.tcl # Configuration CONFIG_TCL_FILES = ./config.tcl diff --git a/src/eth/example/KR260/fpga/fpga_10g/config.tcl b/src/eth/example/KR260/fpga/fpga_10g/config.tcl index fe5171b..4359e24 100644 --- a/src/eth/example/KR260/fpga/fpga_10g/config.tcl +++ b/src/eth/example/KR260/fpga/fpga_10g/config.tcl @@ -8,9 +8,10 @@ set params [dict create] -# SFP+ rate -# 0 for 1G, 1 for 10G -dict set params SFP_RATE "1" +# 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 {} diff --git a/src/eth/example/KR260/fpga/fpga_1g/Makefile b/src/eth/example/KR260/fpga/fpga_1g/Makefile index db1b564..c1844d8 100644 --- a/src/eth/example/KR260/fpga/fpga_1g/Makefile +++ b/src/eth/example/KR260/fpga/fpga_1g/Makefile @@ -18,7 +18,7 @@ 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/taxi_eth_mac_1g_fifo.f +SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_mac_1g_basex_us.f SYN_FILES += $(TAXI_SRC_DIR)/eth/rtl/taxi_eth_mac_1g_rgmii_fifo.f SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv @@ -37,7 +37,7 @@ 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 = ../ip/basex_pcs_pma_0.tcl +IP_TCL_FILES += $(TAXI_SRC_DIR)/eth/rtl/us/taxi_eth_phy_1g_basex_us_gth_156.tcl # Configuration CONFIG_TCL_FILES = ./config.tcl diff --git a/src/eth/example/KR260/fpga/fpga_1g/config.tcl b/src/eth/example/KR260/fpga/fpga_1g/config.tcl index 168762b..ab45ff6 100644 --- a/src/eth/example/KR260/fpga/fpga_1g/config.tcl +++ b/src/eth/example/KR260/fpga/fpga_1g/config.tcl @@ -8,9 +8,10 @@ set params [dict create] -# SFP+ rate -# 0 for 1G, 1 for 10G -dict set params SFP_RATE "0" +# 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 {} diff --git a/src/eth/example/KR260/fpga/ip/basex_pcs_pma_0.tcl b/src/eth/example/KR260/fpga/ip/basex_pcs_pma_0.tcl deleted file mode 100644 index a4c6f27..0000000 --- a/src/eth/example/KR260/fpga/ip/basex_pcs_pma_0.tcl +++ /dev/null @@ -1,21 +0,0 @@ -# SPDX-License-Identifier: MIT -# -# Copyright (c) 2025 FPGA Ninja, LLC -# -# Authors: -# - Alex Forencich -# - -create_ip -name gig_ethernet_pcs_pma -vendor xilinx.com -library ip -module_name basex_pcs_pma_0 - -set_property -dict [list \ - CONFIG.Standard {1000BASEX} \ - CONFIG.Physical_Interface {Transceiver} \ - CONFIG.Management_Interface {false} \ - CONFIG.Auto_Negotiation {false} \ - CONFIG.TransceiverControl {false} \ - CONFIG.RefClkRate {156.25} \ - CONFIG.DrpClkRate {62.5} \ - CONFIG.SupportLevel {Include_Shared_Logic_in_Core} \ - CONFIG.GT_Location {X0Y6} \ -] [get_ips basex_pcs_pma_0] diff --git a/src/eth/example/KR260/fpga/rtl/fpga.sv b/src/eth/example/KR260/fpga/rtl/fpga.sv index 85c1b59..23fa9bf 100644 --- a/src/eth/example/KR260/fpga/rtl/fpga.sv +++ b/src/eth/example/KR260/fpga/rtl/fpga.sv @@ -25,8 +25,10 @@ module fpga # parameter string FAMILY = "zynquplus", // Use 90 degree clock for RGMII transmit parameter logic USE_CLK90 = 1'b1, - // SFP rate selection (0 for 1G, 1 for 10G) - parameter logic SFP_RATE = 1'b1 + // MAC configuration + parameter logic CFG_LOW_LATENCY = 1'b1, + parameter logic COMBINED_MAC_PCS = 1'b1, + parameter MAC_DATA_W = 32 ) ( /* @@ -388,106 +390,14 @@ phy3_rx_ctl_idelay ( .CNTVALUEOUT() ); -// SFP -wire sfp_tx_p_int; -wire sfp_tx_n_int; - -wire sfp_gmii_clk_int; -wire sfp_gmii_rst_int; -wire sfp_gmii_clk_en_int = 1'b1; -wire [7:0] sfp_gmii_txd_int; -wire sfp_gmii_tx_en_int; -wire sfp_gmii_tx_er_int; -wire [7:0] sfp_gmii_rxd_int; -wire sfp_gmii_rx_dv_int; -wire sfp_gmii_rx_er_int; - -if (SFP_RATE == 0) begin : sfp_phy - // 1000BASE-X - - wire sfp_gmii_txuserclk2; - wire sfp_gmii_resetdone; - - assign sfp_gmii_clk_int = sfp_gmii_txuserclk2; - - taxi_sync_reset #( - .N(4) - ) - sync_reset_sfp_inst ( - .clk(sfp_gmii_clk_int), - .rst(rst_125mhz_int || !sfp_gmii_resetdone), - .out(sfp_gmii_rst_int) - ); - - wire [15:0] sfp_status_vect; - - wire sfp_status_link_status = sfp_status_vect[0]; - wire sfp_status_link_synchronization = sfp_status_vect[1]; - wire sfp_status_rudi_c = sfp_status_vect[2]; - wire sfp_status_rudi_i = sfp_status_vect[3]; - wire sfp_status_rudi_invalid = sfp_status_vect[4]; - wire sfp_status_rxdisperr = sfp_status_vect[5]; - wire sfp_status_rxnotintable = sfp_status_vect[6]; - wire sfp_status_phy_link_status = sfp_status_vect[7]; - wire [1:0] sfp_status_remote_fault_encdg = sfp_status_vect[9:8]; - wire [1:0] sfp_status_speed = sfp_status_vect[11:10]; - wire sfp_status_duplex = sfp_status_vect[12]; - wire sfp_status_remote_fault = sfp_status_vect[13]; - wire [1:0] sfp_status_pause = sfp_status_vect[15:14]; - - wire [4:0] sfp_config_vect; - - assign sfp_config_vect[4] = 1'b0; // autonegotiation enable - assign sfp_config_vect[3] = 1'b0; // isolate - assign sfp_config_vect[2] = 1'b0; // power down - assign sfp_config_vect[1] = 1'b0; // loopback enable - assign sfp_config_vect[0] = 1'b0; // unidirectional enable - - basex_pcs_pma_0 - sfp_pcspma ( - .gtrefclk_p(sfp_mgt_refclk_p), - .gtrefclk_n(sfp_mgt_refclk_n), - .gtrefclk_out(), - .txn(sfp_tx_n), - .txp(sfp_tx_p), - .rxn(sfp_rx_n), - .rxp(sfp_rx_p), - .independent_clock_bufg(clk_62mhz_int), - .userclk_out(), - .userclk2_out(sfp_gmii_txuserclk2), - .rxuserclk_out(), - .rxuserclk2_out(), - .gtpowergood(), - .resetdone(sfp_gmii_resetdone), - .pma_reset_out(), - .mmcm_locked_out(), - .gmii_txd(sfp_gmii_txd_int), - .gmii_tx_en(sfp_gmii_tx_en_int), - .gmii_tx_er(sfp_gmii_tx_er_int), - .gmii_rxd(sfp_gmii_rxd_int), - .gmii_rx_dv(sfp_gmii_rx_dv_int), - .gmii_rx_er(sfp_gmii_rx_er_int), - .gmii_isolate(), - .configuration_vector(sfp_config_vect), - .status_vector(sfp_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 - fpga_core #( .SIM(SIM), .VENDOR(VENDOR), .FAMILY(FAMILY), .USE_CLK90(USE_CLK90), - .SFP_RATE(SFP_RATE) + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), + .COMBINED_MAC_PCS(COMBINED_MAC_PCS), + .MAC_DATA_W(MAC_DATA_W) ) core_inst ( /* @@ -528,21 +438,11 @@ core_inst ( */ .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_tx_p(sfp_tx_p), + .sfp_tx_n(sfp_tx_n), .sfp_mgt_refclk_p(sfp_mgt_refclk_p), .sfp_mgt_refclk_n(sfp_mgt_refclk_n), - .sfp_gmii_clk(sfp_gmii_clk_int), - .sfp_gmii_rst(sfp_gmii_rst_int), - .sfp_gmii_clk_en(sfp_gmii_clk_en_int), - .sfp_gmii_rxd(sfp_gmii_rxd_int), - .sfp_gmii_rx_dv(sfp_gmii_rx_dv_int), - .sfp_gmii_rx_er(sfp_gmii_rx_er_int), - .sfp_gmii_txd(sfp_gmii_txd_int), - .sfp_gmii_tx_en(sfp_gmii_tx_en_int), - .sfp_gmii_tx_er(sfp_gmii_tx_er_int), - .sfp_tx_disable(sfp_tx_disable), .sfp_tx_fault(sfp_tx_fault_int), .sfp_rx_los(sfp_rx_los_int), diff --git a/src/eth/example/KR260/fpga/rtl/fpga_core.sv b/src/eth/example/KR260/fpga/rtl/fpga_core.sv index e61f625..6d0238c 100644 --- a/src/eth/example/KR260/fpga/rtl/fpga_core.sv +++ b/src/eth/example/KR260/fpga/rtl/fpga_core.sv @@ -25,8 +25,10 @@ module fpga_core # parameter string FAMILY = "zynquplus", // Use 90 degree clock for RGMII transmit parameter logic USE_CLK90 = 1'b1, - // SFP rate selection (0 for 1G, 1 for 10G) - parameter logic SFP_RATE = 1'b1 + // MAC configuration + parameter logic CFG_LOW_LATENCY = 1'b1, + parameter logic COMBINED_MAC_PCS = 1'b1, + parameter MAC_DATA_W = 32 ) ( /* @@ -72,16 +74,6 @@ module fpga_core # input wire logic sfp_mgt_refclk_p, input wire logic sfp_mgt_refclk_n, - input wire logic sfp_gmii_clk, - input wire logic sfp_gmii_rst, - input wire logic sfp_gmii_clk_en, - input wire logic [7:0] sfp_gmii_rxd, - input wire logic sfp_gmii_rx_dv, - input wire logic sfp_gmii_rx_er, - output wire logic [7:0] sfp_gmii_txd, - output wire logic sfp_gmii_tx_en, - output wire logic sfp_gmii_tx_er, - output wire logic sfp_tx_disable, input wire logic sfp_tx_fault, input wire logic sfp_rx_los, @@ -254,55 +246,221 @@ phy3_eth_mac_inst ( // SFP+ assign sfp_tx_disable = 1'b0; -if (SFP_RATE == 0) begin : sfp_mac +wire sfp_tx_clk[1]; +wire sfp_tx_rst[1]; +wire sfp_rx_clk[1]; +wire sfp_rx_rst[1]; - taxi_axis_if #(.DATA_W(8), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_eth(); - taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl(); - 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(); +wire sfp_rx_status[1]; - taxi_eth_mac_1g_fifo #( - .STAT_EN(1'b0), - .TX_FIFO_DEPTH(16384), - .TX_FRAME_FIFO(1), - .RX_FIFO_DEPTH(16384), - .RX_FRAME_FIFO(1) +wire sfp_gtpowergood; + +wire sfp_mgt_refclk; +wire sfp_mgt_refclk_int; +wire sfp_mgt_refclk_bufg; + +wire sfp_rst; + +taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_tx[1](); +taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[1](); +taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_rx[1](); +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(); + +if (SIM) begin + + assign sfp_mgt_refclk = sfp_mgt_refclk_p; + assign sfp_mgt_refclk_int = sfp_mgt_refclk_p; + assign sfp_mgt_refclk_bufg = sfp_mgt_refclk_int; + +end else begin + + IBUFDS_GTE4 ibufds_gte3_sfp_mgt_refclk_inst ( + .I (sfp_mgt_refclk_p), + .IB (sfp_mgt_refclk_n), + .CEB (1'b0), + .O (sfp_mgt_refclk), + .ODIV2 (sfp_mgt_refclk_int) + ); + + BUFG_GT bufg_gt_sfp_mgt_refclk_inst ( + .CE (sfp_gtpowergood), + .CEMASK (1'b1), + .CLR (1'b0), + .CLRMASK (1'b1), + .DIV (3'd0), + .I (sfp_mgt_refclk_int), + .O (sfp_mgt_refclk_bufg) + ); + +end + +taxi_sync_reset #( + .N(4) +) +sfp_sync_reset_inst ( + .clk(sfp_mgt_refclk_bufg), + .rst(rst), + .out(sfp_rst) +); + +taxi_apb_if #( + .ADDR_W(18), + .DATA_W(16) +) +gt_apb_ctrl(); + +if (MAC_DATA_W == 16) begin : sfp_mac + + taxi_eth_mac_1g_basex_us #( + .SIM(SIM), + .VENDOR(VENDOR), + .FAMILY(FAMILY), + + .CNT(1), + + // GT config + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), + + // GT type + .GT_TYPE("GTH"), + + // 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_eth_mac_inst ( - .rx_clk(sfp_gmii_clk), - .rx_rst(sfp_gmii_rst), - .tx_clk(sfp_gmii_clk), - .tx_rst(sfp_gmii_rst), - .logic_clk(clk), - .logic_rst(rst), + sfp_mac_inst ( + .xcvr_ctrl_clk(clk), + .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), + .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), + .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('{1{1'b0}}), + .rx_rst_out(sfp_rx_rst), + .tx_clk(sfp_tx_clk), + .tx_rst_in('{1{1'b0}}), + .tx_rst_out(sfp_tx_rst), /* * Transmit interface (AXI stream) */ - .s_axis_tx(axis_sfp_eth), + .s_axis_tx(axis_sfp_tx), .m_axis_tx_cpl(axis_sfp_tx_cpl), /* * Receive interface (AXI stream) */ - .m_axis_rx(axis_sfp_eth), + .m_axis_rx(axis_sfp_rx), /* - * GMII interface + * Autonegotiation */ - .gmii_rxd(sfp_gmii_rxd), - .gmii_rx_dv(sfp_gmii_rx_dv), - .gmii_rx_er(sfp_gmii_rx_er), - .gmii_txd(sfp_gmii_txd), - .gmii_tx_en(sfp_gmii_tx_en), - .gmii_tx_er(sfp_gmii_tx_er), + .an_en('{1{1'b1}}), + .an_restart('{1{1'b0}}), + .an_speedup('{1{1'b0}}), + .an_timeout_en('{1{1'b1}}), + .an_sgmii_en('{1{1'b0}}), + .an_sgmii_auto('{1{1'b1}}), + .an_intr(), + .an_running(), + .an_complete(), + .an_timeout(), + .an_sgmii_mode(), + .an_adv_ability_basex('{1{16'h0020}}), + .an_adv_ability_sgmii('{1{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(), /* - * Control + * PTP clock */ - .rx_clk_enable(sfp_gmii_clk_en), - .tx_clk_enable(sfp_gmii_clk_en), - .rx_mii_select(1'b0), - .tx_mii_select(1'b0), + .ptp_clk(1'b0), + .ptp_rst(1'b0), + .ptp_sample_clk(1'b0), + .ptp_td_sdi(1'b0), + .tx_ptp_ts_in('{1{'0}}), + .tx_ptp_ts_out(), + .tx_ptp_ts_step_out(), + .tx_ptp_locked(), + .rx_ptp_ts_in('{1{'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('{1{1'b0}}), + .tx_lfc_resend('{1{1'b0}}), + .rx_lfc_en('{1{1'b0}}), + .rx_lfc_req(), + .rx_lfc_ack('{1{1'b0}}), + + /* + * Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC) + */ + .tx_pfc_req('{1{'0}}), + .tx_pfc_resend('{1{1'b0}}), + .rx_pfc_en('{1{'0}}), + .rx_pfc_req(), + .rx_pfc_ack('{1{'0}}), + + /* + * Pause interface + */ + .tx_lfc_pause_en('{1{1'b0}}), + .tx_pause_req('{1{1'b0}}), + .tx_pause_ack(), /* * Statistics @@ -314,93 +472,106 @@ if (SFP_RATE == 0) begin : sfp_mac /* * 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(), + .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('{1{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(1'b1), - .cfg_tx_min_pkt_len(8'd60-1), - .cfg_tx_max_pkt_len(16'd9218-1), - .cfg_tx_ifg(8'd12), - .cfg_tx_enable(1'b1), - .cfg_rx_max_pkt_len(16'd9218-1), - .cfg_rx_enable(1'b1) + .cfg_tx_pad_en('{1{1'b1}}), + .cfg_tx_min_pkt_len('{1{8'd60-1}}), + .cfg_tx_max_pkt_len('{1{16'd9218-1}}), + .cfg_tx_ifg('{1{8'd12}}), + .cfg_tx_enable('{1{1'b1}}), + .cfg_rx_max_pkt_len('{1{16'd9218-1}}), + .cfg_rx_enable('{1{1'b1}}), + .cfg_tx_prbs31_enable('{1{1'b0}}), + .cfg_rx_prbs31_enable('{1{1'b0}}), + .cfg_mcf_rx_eth_dst_mcast('{1{48'h01_80_C2_00_00_01}}), + .cfg_mcf_rx_check_eth_dst_mcast('{1{1'b1}}), + .cfg_mcf_rx_eth_dst_ucast('{1{48'd0}}), + .cfg_mcf_rx_check_eth_dst_ucast('{1{1'b0}}), + .cfg_mcf_rx_eth_src('{1{48'd0}}), + .cfg_mcf_rx_check_eth_src('{1{1'b0}}), + .cfg_mcf_rx_eth_type('{1{16'h8808}}), + .cfg_mcf_rx_opcode_lfc('{1{16'h0001}}), + .cfg_mcf_rx_check_opcode_lfc('{1{1'b1}}), + .cfg_mcf_rx_opcode_pfc('{1{16'h0101}}), + .cfg_mcf_rx_check_opcode_pfc('{1{1'b1}}), + .cfg_mcf_rx_forward('{1{1'b0}}), + .cfg_mcf_rx_enable('{1{1'b0}}), + .cfg_tx_lfc_eth_dst('{1{48'h01_80_C2_00_00_01}}), + .cfg_tx_lfc_eth_src('{1{48'h80_23_31_43_54_4C}}), + .cfg_tx_lfc_eth_type('{1{16'h8808}}), + .cfg_tx_lfc_opcode('{1{16'h0001}}), + .cfg_tx_lfc_en('{1{1'b0}}), + .cfg_tx_lfc_quanta('{1{16'hffff}}), + .cfg_tx_lfc_refresh('{1{16'h7fff}}), + .cfg_tx_pfc_eth_dst('{1{48'h01_80_C2_00_00_01}}), + .cfg_tx_pfc_eth_src('{1{48'h80_23_31_43_54_4C}}), + .cfg_tx_pfc_eth_type('{1{16'h8808}}), + .cfg_tx_pfc_opcode('{1{16'h0101}}), + .cfg_tx_pfc_en('{1{1'b0}}), + .cfg_tx_pfc_quanta('{1{'{8{16'hffff}}}}), + .cfg_tx_pfc_refresh('{1{'{8{16'h7fff}}}}), + .cfg_rx_lfc_opcode('{1{16'h0001}}), + .cfg_rx_lfc_en('{1{1'b0}}), + .cfg_rx_pfc_opcode('{1{16'h0101}}), + .cfg_rx_pfc_en('{1{1'b0}}) ); end else begin : sfp_mac - wire sfp_tx_clk[1]; - wire sfp_tx_rst[1]; - wire sfp_rx_clk[1]; - wire sfp_rx_rst[1]; - - wire sfp_rx_status[1]; - - wire sfp_gtpowergood; - - wire sfp_mgt_refclk; - wire sfp_mgt_refclk_int; - wire sfp_mgt_refclk_bufg; - - wire sfp_rst; - - taxi_axis_if #(.DATA_W(32), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_tx[1](); - taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[1](); - taxi_axis_if #(.DATA_W(32), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_rx[1](); - 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(); - - if (SIM) begin - - assign sfp_mgt_refclk = sfp_mgt_refclk_p; - assign sfp_mgt_refclk_int = sfp_mgt_refclk_p; - assign sfp_mgt_refclk_bufg = sfp_mgt_refclk_int; - - end else begin - - IBUFDS_GTE4 ibufds_gte3_sfp_mgt_refclk_inst ( - .I (sfp_mgt_refclk_p), - .IB (sfp_mgt_refclk_n), - .CEB (1'b0), - .O (sfp_mgt_refclk), - .ODIV2 (sfp_mgt_refclk_int) - ); - - BUFG_GT bufg_gt_sfp_mgt_refclk_inst ( - .CE (sfp_gtpowergood), - .CEMASK (1'b1), - .CLR (1'b0), - .CLRMASK (1'b1), - .DIV (3'd0), - .I (sfp_mgt_refclk_int), - .O (sfp_mgt_refclk_bufg) - ); - - end - - taxi_sync_reset #( - .N(4) - ) - sfp_sync_reset_inst ( - .clk(sfp_mgt_refclk_bufg), - .rst(rst), - .out(sfp_rst) - ); - - taxi_apb_if #( - .ADDR_W(18), - .DATA_W(16) - ) - gt_apb_ctrl(); - taxi_eth_mac_25g_us #( .SIM(SIM), .VENDOR(VENDOR), @@ -409,14 +580,15 @@ end else begin : sfp_mac .CNT(1), // GT config - .CFG_LOW_LATENCY(1), + .CFG_LOW_LATENCY(CFG_LOW_LATENCY), // GT type .GT_TYPE("GTH"), // PHY parameters + .COMBINED_MAC_PCS(COMBINED_MAC_PCS), .DATA_W(axis_sfp_tx[0].DATA_W), - .USXGMII_EN(1'b1), + .USXGMII_EN(COMBINED_MAC_PCS), .DIC_EN(1'b1), .PTP_TS_EN(1'b0), .PTP_TD_EN(1'b0), @@ -655,6 +827,10 @@ end else begin : sfp_mac .cfg_rx_pfc_en('{1{1'b0}}) ); +end + +for (genvar n = 0; n < $size(axis_sfp_tx); n = n + 1) begin : sfp_ch + taxi_axis_async_fifo #( .DEPTH(16384), .RAM_PIPELINE(2), @@ -665,20 +841,20 @@ end else begin : sfp_mac .DROP_BAD_FRAME(1), .DROP_WHEN_FULL(1) ) - sfp_mac_fifo ( + ch_fifo ( /* * AXI4-Stream input (sink) */ - .s_clk(sfp_rx_clk[0]), - .s_rst(sfp_rx_rst[0]), - .s_axis(axis_sfp_rx[0]), + .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[0]), - .m_rst(sfp_tx_rst[0]), - .m_axis(axis_sfp_tx[0]), + .m_clk(sfp_tx_clk[n]), + .m_rst(sfp_tx_rst[n]), + .m_axis(axis_sfp_tx[n]), /* * Pause diff --git a/src/eth/example/KR260/fpga/tb/fpga_core/Makefile b/src/eth/example/KR260/fpga/tb/fpga_core/Makefile index f6cc4e7..b7145ae 100644 --- a/src/eth/example/KR260/fpga/tb/fpga_core/Makefile +++ b/src/eth/example/KR260/fpga/tb/fpga_core/Makefile @@ -23,8 +23,8 @@ COCOTB_TOPLEVEL = $(DUT) MODULE = $(COCOTB_TEST_MODULES) TOPLEVEL = $(COCOTB_TOPLEVEL) VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv -VERILOG_SOURCES += $(TAXI_SRC_DIR)/eth/rtl/taxi_eth_mac_1g_fifo.f 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)/eth/rtl/taxi_eth_mac_1g_rgmii_fifo.f VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv @@ -40,7 +40,9 @@ export PARAM_SIM := "1'b1" export PARAM_VENDOR := "\"XILINX\"" export PARAM_FAMILY := "\"zynquplus\"" export PARAM_USE_CLK90 := "1'b1" -export PARAM_SFP_RATE := "1'b1" +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/KR260/fpga/tb/fpga_core/basex.py b/src/eth/example/KR260/fpga/tb/fpga_core/basex.py new file mode 120000 index 0000000..b976cc4 --- /dev/null +++ b/src/eth/example/KR260/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/KR260/fpga/tb/fpga_core/test_fpga_core.py b/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py index 6c8b3c0..a2fab61 100644 --- a/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py +++ b/src/eth/example/KR260/fpga/tb/fpga_core/test_fpga_core.py @@ -20,16 +20,18 @@ import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge, Timer, Combine -from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink, RgmiiPhy +from cocotbext.eth import GmiiFrame, RgmiiPhy from cocotbext.eth import XgmiiFrame 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] @@ -50,68 +52,95 @@ class TB: self.sfp_sources = [] self.sfp_sinks = [] - if dut.SFP_RATE.value == 0: - cocotb.start_soon(Clock(dut.sfp_gmii_clk, 8, units="ns").start()) + cocotb.start_soon(Clock(dut.sfp_mgt_refclk_p, 6.4, units="ns").start()) - self.sfp_sources.append(GmiiSource(dut.sfp_gmii_rxd, dut.sfp_gmii_rx_er, dut.sfp_gmii_rx_dv, - dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)) - self.sfp_sinks.append(GmiiSink(dut.sfp_gmii_txd, dut.sfp_gmii_tx_er, dut.sfp_gmii_tx_en, - dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)) - else: - cocotb.start_soon(Clock(dut.sfp_mgt_refclk_p, 6.4, units="ns").start()) - - ch = dut.sfp_mac.sfp_mac_inst.ch[0] + 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 + )) cocotb.start_soon(self._run_clk()) async def init(self): self.dut.rst.setimmediatevalue(0) - self.dut.sfp_gmii_rst.setimmediatevalue(0) for k in range(10): await RisingEdge(self.dut.clk) self.dut.rst.value = 1 - self.dut.sfp_gmii_rst.value = 1 for k in range(10): await RisingEdge(self.dut.clk) self.dut.rst.value = 0 - self.dut.sfp_gmii_rst.value = 0 for k in range(10): await RisingEdge(self.dut.clk) @@ -132,51 +161,7 @@ class TB: async def mac_test(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(GmiiFrame.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() - assert rx_frame.error is None - - 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(GmiiFrame.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() - assert rx_frame.error is None - - tb.log.info("MAC test done") - - -async def mac_test_10g(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) + sink.clear() tb.log.info("Multiple small packets") @@ -224,6 +209,10 @@ async def run_test(dut): tests = [] + tb.log.info("Wait for block lock") + for k in range(1200): + await RisingEdge(dut.clk) + tb.log.info("Start BASE-T MAC loopback test on PHY2") tests.append(cocotb.start_soon(mac_test(tb, tb.baset_phy2.rx, tb.baset_phy2.tx))) @@ -232,12 +221,9 @@ async def run_test(dut): tests.append(cocotb.start_soon(mac_test(tb, tb.baset_phy3.rx, tb.baset_phy3.tx))) - if dut.SFP_RATE.value == 0: - tb.log.info("Start 1G SFP MAC loopback test") - tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_sources[0], tb.sfp_sinks[0]))) - else: - tb.log.info("Start 10G SFP MAC loopback test") - tests.append(cocotb.start_soon(mac_test_10g(tb, tb.sfp_sources[0], tb.sfp_sinks[0]))) + for k in range(len(tb.sfp_sources)): + 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) @@ -266,16 +252,16 @@ def process_f_files(files): return list(lst.values()) -@pytest.mark.parametrize("sfp_rate", [0, 1]) -def test_fpga_core(request, sfp_rate): +@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 verilog_sources = [ os.path.join(rtl_dir, f"{dut}.sv"), - os.path.join(taxi_src_dir, "eth", "rtl", "taxi_eth_mac_1g_fifo.f"), 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, "eth", "rtl", "taxi_eth_mac_1g_rgmii_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"), @@ -289,7 +275,9 @@ def test_fpga_core(request, sfp_rate): parameters['VENDOR'] = "\"XILINX\"" parameters['FAMILY'] = "\"zynquplus\"" parameters['USE_CLK90'] = "1'b1" - parameters['SFP_RATE'] = f"1'b{sfp_rate}" + 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()}