eth: Update KR260 1000BASE-X example design implementation

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-08-08 22:15:35 -07:00
parent dbb561497f
commit 511b65e4a5
10 changed files with 416 additions and 368 deletions

View File

@@ -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 XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP # 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 # Configuration
CONFIG_TCL_FILES = ./config.tcl CONFIG_TCL_FILES = ./config.tcl

View File

@@ -8,9 +8,10 @@
set params [dict create] set params [dict create]
# SFP+ rate # MAC configuration
# 0 for 1G, 1 for 10G dict set params CFG_LOW_LATENCY "1"
dict set params SFP_RATE "1" dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "32"
# apply parameters to top-level # apply parameters to top-level
set param_list {} set param_list {}

View File

@@ -18,7 +18,7 @@ TAXI_SRC_DIR = $(LIB_DIR)/taxi/src
# Files for synthesis # Files for synthesis
SYN_FILES = $(RTL_DIR)/fpga.sv SYN_FILES = $(RTL_DIR)/fpga.sv
SYN_FILES += $(RTL_DIR)/fpga_core.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)/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_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.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 XDC_FILES += $(TAXI_SRC_DIR)/sync/syn/vivado/taxi_sync_signal.tcl
# IP # 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 # Configuration
CONFIG_TCL_FILES = ./config.tcl CONFIG_TCL_FILES = ./config.tcl

View File

@@ -8,9 +8,10 @@
set params [dict create] set params [dict create]
# SFP+ rate # MAC configuration
# 0 for 1G, 1 for 10G dict set params CFG_LOW_LATENCY "1"
dict set params SFP_RATE "0" dict set params COMBINED_MAC_PCS "1"
dict set params MAC_DATA_W "16"
# apply parameters to top-level # apply parameters to top-level
set param_list {} set param_list {}

View File

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

View File

@@ -25,8 +25,10 @@ module fpga #
parameter string FAMILY = "zynquplus", parameter string FAMILY = "zynquplus",
// Use 90 degree clock for RGMII transmit // Use 90 degree clock for RGMII transmit
parameter logic USE_CLK90 = 1'b1, parameter logic USE_CLK90 = 1'b1,
// SFP rate selection (0 for 1G, 1 for 10G) // MAC configuration
parameter logic SFP_RATE = 1'b1 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() .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 #( fpga_core #(
.SIM(SIM), .SIM(SIM),
.VENDOR(VENDOR), .VENDOR(VENDOR),
.FAMILY(FAMILY), .FAMILY(FAMILY),
.USE_CLK90(USE_CLK90), .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 ( core_inst (
/* /*
@@ -528,21 +438,11 @@ core_inst (
*/ */
.sfp_rx_p(sfp_rx_p), .sfp_rx_p(sfp_rx_p),
.sfp_rx_n(sfp_rx_n), .sfp_rx_n(sfp_rx_n),
.sfp_tx_p(sfp_tx_p_int), .sfp_tx_p(sfp_tx_p),
.sfp_tx_n(sfp_tx_n_int), .sfp_tx_n(sfp_tx_n),
.sfp_mgt_refclk_p(sfp_mgt_refclk_p), .sfp_mgt_refclk_p(sfp_mgt_refclk_p),
.sfp_mgt_refclk_n(sfp_mgt_refclk_n), .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_disable(sfp_tx_disable),
.sfp_tx_fault(sfp_tx_fault_int), .sfp_tx_fault(sfp_tx_fault_int),
.sfp_rx_los(sfp_rx_los_int), .sfp_rx_los(sfp_rx_los_int),

View File

@@ -25,8 +25,10 @@ module fpga_core #
parameter string FAMILY = "zynquplus", parameter string FAMILY = "zynquplus",
// Use 90 degree clock for RGMII transmit // Use 90 degree clock for RGMII transmit
parameter logic USE_CLK90 = 1'b1, parameter logic USE_CLK90 = 1'b1,
// SFP rate selection (0 for 1G, 1 for 10G) // MAC configuration
parameter logic SFP_RATE = 1'b1 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_p,
input wire logic sfp_mgt_refclk_n, 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, output wire logic sfp_tx_disable,
input wire logic sfp_tx_fault, input wire logic sfp_tx_fault,
input wire logic sfp_rx_los, input wire logic sfp_rx_los,
@@ -254,55 +246,221 @@ phy3_eth_mac_inst (
// SFP+ // SFP+
assign sfp_tx_disable = 1'b0; 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(); wire sfp_rx_status[1];
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();
taxi_eth_mac_1g_fifo #( wire sfp_gtpowergood;
.STAT_EN(1'b0),
.TX_FIFO_DEPTH(16384), wire sfp_mgt_refclk;
.TX_FRAME_FIFO(1), wire sfp_mgt_refclk_int;
.RX_FIFO_DEPTH(16384), wire sfp_mgt_refclk_bufg;
.RX_FRAME_FIFO(1)
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 ( sfp_mac_inst (
.rx_clk(sfp_gmii_clk), .xcvr_ctrl_clk(clk),
.rx_rst(sfp_gmii_rst), .xcvr_ctrl_rst(sfp_rst),
.tx_clk(sfp_gmii_clk),
.tx_rst(sfp_gmii_rst), /*
.logic_clk(clk), * Transceiver control
.logic_rst(rst), */
.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) * Transmit interface (AXI stream)
*/ */
.s_axis_tx(axis_sfp_eth), .s_axis_tx(axis_sfp_tx),
.m_axis_tx_cpl(axis_sfp_tx_cpl), .m_axis_tx_cpl(axis_sfp_tx_cpl),
/* /*
* Receive interface (AXI stream) * Receive interface (AXI stream)
*/ */
.m_axis_rx(axis_sfp_eth), .m_axis_rx(axis_sfp_rx),
/* /*
* GMII interface * Autonegotiation
*/ */
.gmii_rxd(sfp_gmii_rxd), .an_en('{1{1'b1}}),
.gmii_rx_dv(sfp_gmii_rx_dv), .an_restart('{1{1'b0}}),
.gmii_rx_er(sfp_gmii_rx_er), .an_speedup('{1{1'b0}}),
.gmii_txd(sfp_gmii_txd), .an_timeout_en('{1{1'b1}}),
.gmii_tx_en(sfp_gmii_tx_en), .an_sgmii_en('{1{1'b0}}),
.gmii_tx_er(sfp_gmii_tx_er), .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), .ptp_clk(1'b0),
.tx_clk_enable(sfp_gmii_clk_en), .ptp_rst(1'b0),
.rx_mii_select(1'b0), .ptp_sample_clk(1'b0),
.tx_mii_select(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 * Statistics
@@ -314,93 +472,106 @@ if (SFP_RATE == 0) begin : sfp_mac
/* /*
* Status * Status
*/ */
.tx_error_underflow(), .tx_start_packet(),
.tx_fifo_overflow(), .stat_tx_byte(),
.tx_fifo_bad_frame(), .stat_tx_pkt_len(),
.tx_fifo_good_frame(), .stat_tx_pkt_ucast(),
.rx_error_bad_frame(), .stat_tx_pkt_mcast(),
.rx_error_bad_fcs(), .stat_tx_pkt_bcast(),
.rx_fifo_overflow(), .stat_tx_pkt_vlan(),
.rx_fifo_bad_frame(), .stat_tx_pkt_good(),
.rx_fifo_good_frame(), .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 * Configuration
*/ */
.cfg_tx_pad_en(1'b1), .cfg_tx_pad_en('{1{1'b1}}),
.cfg_tx_min_pkt_len(8'd60-1), .cfg_tx_min_pkt_len('{1{8'd60-1}}),
.cfg_tx_max_pkt_len(16'd9218-1), .cfg_tx_max_pkt_len('{1{16'd9218-1}}),
.cfg_tx_ifg(8'd12), .cfg_tx_ifg('{1{8'd12}}),
.cfg_tx_enable(1'b1), .cfg_tx_enable('{1{1'b1}}),
.cfg_rx_max_pkt_len(16'd9218-1), .cfg_rx_max_pkt_len('{1{16'd9218-1}}),
.cfg_rx_enable(1'b1) .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 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 #( taxi_eth_mac_25g_us #(
.SIM(SIM), .SIM(SIM),
.VENDOR(VENDOR), .VENDOR(VENDOR),
@@ -409,14 +580,15 @@ end else begin : sfp_mac
.CNT(1), .CNT(1),
// GT config // GT config
.CFG_LOW_LATENCY(1), .CFG_LOW_LATENCY(CFG_LOW_LATENCY),
// GT type // GT type
.GT_TYPE("GTH"), .GT_TYPE("GTH"),
// PHY parameters // PHY parameters
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.DATA_W(axis_sfp_tx[0].DATA_W), .DATA_W(axis_sfp_tx[0].DATA_W),
.USXGMII_EN(1'b1), .USXGMII_EN(COMBINED_MAC_PCS),
.DIC_EN(1'b1), .DIC_EN(1'b1),
.PTP_TS_EN(1'b0), .PTP_TS_EN(1'b0),
.PTP_TD_EN(1'b0), .PTP_TD_EN(1'b0),
@@ -655,6 +827,10 @@ end else begin : sfp_mac
.cfg_rx_pfc_en('{1{1'b0}}) .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 #( taxi_axis_async_fifo #(
.DEPTH(16384), .DEPTH(16384),
.RAM_PIPELINE(2), .RAM_PIPELINE(2),
@@ -665,20 +841,20 @@ end else begin : sfp_mac
.DROP_BAD_FRAME(1), .DROP_BAD_FRAME(1),
.DROP_WHEN_FULL(1) .DROP_WHEN_FULL(1)
) )
sfp_mac_fifo ( ch_fifo (
/* /*
* AXI4-Stream input (sink) * AXI4-Stream input (sink)
*/ */
.s_clk(sfp_rx_clk[0]), .s_clk(sfp_rx_clk[n]),
.s_rst(sfp_rx_rst[0]), .s_rst(sfp_rx_rst[n]),
.s_axis(axis_sfp_rx[0]), .s_axis(axis_sfp_rx[n]),
/* /*
* AXI4-Stream output (source) * AXI4-Stream output (source)
*/ */
.m_clk(sfp_tx_clk[0]), .m_clk(sfp_tx_clk[n]),
.m_rst(sfp_tx_rst[0]), .m_rst(sfp_tx_rst[n]),
.m_axis(axis_sfp_tx[0]), .m_axis(axis_sfp_tx[n]),
/* /*
* Pause * Pause

View File

@@ -23,8 +23,8 @@ COCOTB_TOPLEVEL = $(DUT)
MODULE = $(COCOTB_TEST_MODULES) MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL) TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += $(RTL_DIR)/$(DUT).sv 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_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)/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_reset.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.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_VENDOR := "\"XILINX\""
export PARAM_FAMILY := "\"zynquplus\"" export PARAM_FAMILY := "\"zynquplus\""
export PARAM_USE_CLK90 := "1'b1" 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) ifeq ($(SIM), icarus)
PLUSARGS += -fst PLUSARGS += -fst

View File

@@ -0,0 +1 @@
../../lib/taxi/src/eth/tb/basex.py

View File

@@ -20,16 +20,18 @@ import cocotb
from cocotb.clock import Clock from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Timer, Combine 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 from cocotbext.eth import XgmiiFrame
try: try:
from baser import BaseRSerdesSource, BaseRSerdesSink from baser import BaseRSerdesSource, BaseRSerdesSink
from basex import BaseXSerdesSource, BaseXSerdesSink
except ImportError: except ImportError:
# attempt import from current directory # attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__))) sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try: try:
from baser import BaseRSerdesSource, BaseRSerdesSink from baser import BaseRSerdesSource, BaseRSerdesSink
from basex import BaseXSerdesSource, BaseXSerdesSink
finally: finally:
del sys.path[0] del sys.path[0]
@@ -50,68 +52,95 @@ class TB:
self.sfp_sources = [] self.sfp_sources = []
self.sfp_sinks = [] self.sfp_sinks = []
if dut.SFP_RATE.value == 0: cocotb.start_soon(Clock(dut.sfp_mgt_refclk_p, 6.4, units="ns").start())
cocotb.start_soon(Clock(dut.sfp_gmii_clk, 8, units="ns").start())
self.sfp_sources.append(GmiiSource(dut.sfp_gmii_rxd, dut.sfp_gmii_rx_er, dut.sfp_gmii_rx_dv, for ch in dut.sfp_mac.sfp_mac_inst.ch:
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]
gt_inst = ch.ch_inst.gt.gt_inst gt_inst = ch.ch_inst.gt.gt_inst
if ch.ch_inst.CFG_LOW_LATENCY.value: if dut.MAC_DATA_W.value == 16:
clk = 3.102 if ch.ch_inst.CFG_LOW_LATENCY.value:
gbx_cfg = (66, [64, 65]) 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: else:
clk = 3.2 if ch.ch_inst.DATA_W.value == 64:
gbx_cfg = None 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.tx_clk, clk, units="ns").start())
cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start()) cocotb.start_soon(Clock(gt_inst.rx_clk, clk, units="ns").start())
self.sfp_sources.append(BaseRSerdesSource( self.sfp_sources.append(BaseRSerdesSource(
data=gt_inst.serdes_rx_data, data=gt_inst.serdes_rx_data,
data_valid=gt_inst.serdes_rx_data_valid, data_valid=gt_inst.serdes_rx_data_valid,
hdr=gt_inst.serdes_rx_hdr, hdr=gt_inst.serdes_rx_hdr,
hdr_valid=gt_inst.serdes_rx_hdr_valid, hdr_valid=gt_inst.serdes_rx_hdr_valid,
clock=gt_inst.rx_clk, clock=gt_inst.rx_clk,
slip=gt_inst.serdes_rx_bitslip, slip=gt_inst.serdes_rx_bitslip,
reverse=True, reverse=True,
gbx_cfg=gbx_cfg gbx_cfg=gbx_cfg
)) ))
self.sfp_sinks.append(BaseRSerdesSink( self.sfp_sinks.append(BaseRSerdesSink(
data=gt_inst.serdes_tx_data, data=gt_inst.serdes_tx_data,
data_valid=gt_inst.serdes_tx_data_valid, data_valid=gt_inst.serdes_tx_data_valid,
hdr=gt_inst.serdes_tx_hdr, hdr=gt_inst.serdes_tx_hdr,
hdr_valid=gt_inst.serdes_tx_hdr_valid, hdr_valid=gt_inst.serdes_tx_hdr_valid,
gbx_sync=gt_inst.serdes_tx_gbx_sync, gbx_sync=gt_inst.serdes_tx_gbx_sync,
clock=gt_inst.tx_clk, clock=gt_inst.tx_clk,
reverse=True, reverse=True,
gbx_cfg=gbx_cfg gbx_cfg=gbx_cfg
)) ))
cocotb.start_soon(self._run_clk()) cocotb.start_soon(self._run_clk())
async def init(self): async def init(self):
self.dut.rst.setimmediatevalue(0) self.dut.rst.setimmediatevalue(0)
self.dut.sfp_gmii_rst.setimmediatevalue(0)
for k in range(10): for k in range(10):
await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk)
self.dut.rst.value = 1 self.dut.rst.value = 1
self.dut.sfp_gmii_rst.value = 1
for k in range(10): for k in range(10):
await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk)
self.dut.rst.value = 0 self.dut.rst.value = 0
self.dut.sfp_gmii_rst.value = 0
for k in range(10): for k in range(10):
await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk)
@@ -132,51 +161,7 @@ class TB:
async def mac_test(tb, source, sink): async def mac_test(tb, source, sink):
tb.log.info("Test MAC") tb.log.info("Test MAC")
tb.log.info("Multiple small packets") sink.clear()
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)
tb.log.info("Multiple small packets") tb.log.info("Multiple small packets")
@@ -224,6 +209,10 @@ async def run_test(dut):
tests = [] 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") 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))) 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))) tests.append(cocotb.start_soon(mac_test(tb, tb.baset_phy3.rx, tb.baset_phy3.tx)))
if dut.SFP_RATE.value == 0: for k in range(len(tb.sfp_sources)):
tb.log.info("Start 1G SFP MAC loopback test") tb.log.info("Start SFP %d MAC loopback test", k)
tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_sources[0], tb.sfp_sinks[0]))) tests.append(cocotb.start_soon(mac_test(tb, tb.sfp_sources[k], tb.sfp_sinks[k])))
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])))
await Combine(*tests) await Combine(*tests)
@@ -266,16 +252,16 @@ def process_f_files(files):
return list(lst.values()) return list(lst.values())
@pytest.mark.parametrize("sfp_rate", [0, 1]) @pytest.mark.parametrize("mac_data_w", [16, 32, 64])
def test_fpga_core(request, sfp_rate): def test_fpga_core(request, mac_data_w):
dut = "fpga_core" dut = "fpga_core"
module = os.path.splitext(os.path.basename(__file__))[0] module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = dut toplevel = dut
verilog_sources = [ verilog_sources = [
os.path.join(rtl_dir, f"{dut}.sv"), 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_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, "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_reset.sv"),
os.path.join(taxi_src_dir, "sync", "rtl", "taxi_sync_signal.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['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"zynquplus\"" parameters['FAMILY'] = "\"zynquplus\""
parameters['USE_CLK90'] = "1'b1" 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()} extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}