eth: Update ZCU102 example design to use BASE-X core for 1G

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-06-08 21:24:16 -07:00
parent da63de1c43
commit 7f9e9980ce
10 changed files with 430 additions and 1014 deletions

View File

@@ -12,6 +12,11 @@ set params [dict create]
# 0 for 1G, 1 for 10G
dict set params SFP_RATE "1"
# 10G 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 {

View File

@@ -18,9 +18,10 @@ 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)/xfcp/rtl/taxi_xfcp_if_uart.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.f
SYN_FILES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_stats.f
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_reset.sv
SYN_FILES += $(TAXI_SRC_DIR)/sync/rtl/taxi_sync_signal.sv
@@ -37,8 +38,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 += ../ip/basex_pcs_pma_1.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

View File

@@ -12,6 +12,11 @@ set params [dict create]
# 0 for 1G, 1 for 10G
dict set params SFP_RATE "0"
# 10G 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 {

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 {X0Y10} \
] [get_ips basex_pcs_pma_0]

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_1
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_Example_Design} \
CONFIG.GT_Location {X0Y9} \
] [get_ips basex_pcs_pma_1]

View File

@@ -24,7 +24,11 @@ module fpga #
// device family
parameter string FAMILY = "zynquplus",
// SFP rate selection (0 for 1G, 1 for 10G)
parameter logic SFP_RATE = 1'b1
parameter logic SFP_RATE = 1'b1,
// 10G MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 32
)
(
/*
@@ -83,13 +87,13 @@ wire mmcm_locked;
wire mmcm_clkfb;
IBUFGDS #(
.DIFF_TERM("FALSE"),
.IBUF_LOW_PWR("FALSE")
.DIFF_TERM("FALSE"),
.IBUF_LOW_PWR("FALSE")
)
clk_125mhz_ibufg_inst (
.O (clk_125mhz_ibufg),
.I (clk_125mhz_p),
.IB (clk_125mhz_n)
.O (clk_125mhz_ibufg),
.I (clk_125mhz_p),
.IB (clk_125mhz_n)
);
BUFG
@@ -240,361 +244,14 @@ sync_signal_inst (
.out({uart_rxd_int, uart_rts_int})
);
wire [7:0] led_int;
// SFP+
wire sfp_tx_p_int[4];
wire sfp_tx_n_int[4];
wire sfp0_gmii_clk_int;
wire sfp0_gmii_rst_int;
wire sfp0_gmii_clk_en_int = 1'b1;
wire [7:0] sfp0_gmii_txd_int;
wire sfp0_gmii_tx_en_int;
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 [15:0] sfp0_status_vect;
wire sfp1_gmii_clk_int;
wire sfp1_gmii_rst_int;
wire sfp1_gmii_clk_en_int = 1'b1;
wire [7:0] sfp1_gmii_txd_int;
wire sfp1_gmii_tx_en_int;
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 [15:0] sfp1_status_vect;
wire sfp2_gmii_clk_int;
wire sfp2_gmii_rst_int;
wire sfp2_gmii_clk_en_int = 1'b1;
wire [7:0] sfp2_gmii_txd_int;
wire sfp2_gmii_tx_en_int;
wire sfp2_gmii_tx_er_int;
wire [7:0] sfp2_gmii_rxd_int;
wire sfp2_gmii_rx_dv_int;
wire sfp2_gmii_rx_er_int;
wire [15:0] sfp2_status_vect;
wire sfp3_gmii_clk_int;
wire sfp3_gmii_rst_int;
wire sfp3_gmii_clk_en_int = 1'b1;
wire [7:0] sfp3_gmii_txd_int;
wire sfp3_gmii_tx_en_int;
wire sfp3_gmii_tx_er_int;
wire [7:0] sfp3_gmii_rxd_int;
wire sfp3_gmii_rx_dv_int;
wire sfp3_gmii_rx_er_int;
wire [15:0] sfp3_status_vect;
if (SFP_RATE == 0) begin : sfp_phy
// 1000BASE-X
wire sfp0_gmii_gtrefclk;
wire sfp0_gmii_txuserclk;
wire sfp0_gmii_txuserclk2;
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 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(),
.rxuserclk2_out(),
.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(1'b0),
.rxuserclk2(1'b0),
.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)
);
wire sfp2_gmii_txuserclk2 = sfp0_gmii_txuserclk2;
wire sfp2_gmii_resetdone;
assign sfp2_gmii_clk_int = sfp2_gmii_txuserclk2;
taxi_sync_reset #(
.N(4)
)
sync_reset_sfp2_inst (
.clk(sfp2_gmii_clk_int),
.rst(rst_125mhz_int || !sfp2_gmii_resetdone),
.out(sfp2_gmii_rst_int)
);
wire sfp2_status_link_status = sfp2_status_vect[0];
wire sfp2_status_link_synchronization = sfp2_status_vect[1];
wire sfp2_status_rudi_c = sfp2_status_vect[2];
wire sfp2_status_rudi_i = sfp2_status_vect[3];
wire sfp2_status_rudi_invalid = sfp2_status_vect[4];
wire sfp2_status_rxdisperr = sfp2_status_vect[5];
wire sfp2_status_rxnotintable = sfp2_status_vect[6];
wire sfp2_status_phy_link_status = sfp2_status_vect[7];
wire [1:0] sfp2_status_remote_fault_encdg = sfp2_status_vect[9:8];
wire [1:0] sfp2_status_speed = sfp2_status_vect[11:10];
wire sfp2_status_duplex = sfp2_status_vect[12];
wire sfp2_status_remote_fault = sfp2_status_vect[13];
wire [1:0] sfp2_status_pause = sfp2_status_vect[15:14];
wire [4:0] sfp2_config_vect;
assign sfp2_config_vect[4] = 1'b0; // autonegotiation enable
assign sfp2_config_vect[3] = 1'b0; // isolate
assign sfp2_config_vect[2] = 1'b0; // power down
assign sfp2_config_vect[1] = 1'b0; // loopback enable
assign sfp2_config_vect[0] = 1'b0; // unidirectional enable
basex_pcs_pma_1
sfp2_pcspma (
.gtrefclk(sfp0_gmii_gtrefclk),
.txn(sfp_tx_n[2]),
.txp(sfp_tx_p[2]),
.rxn(sfp_rx_n[2]),
.rxp(sfp_rx_p[2]),
.independent_clock_bufg(clk_62mhz_int),
.txoutclk(),
.gtpowergood(),
.rxoutclk(),
.resetdone(sfp2_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(1'b0),
.rxuserclk2(1'b0),
.gmii_txd(sfp2_gmii_txd_int),
.gmii_tx_en(sfp2_gmii_tx_en_int),
.gmii_tx_er(sfp2_gmii_tx_er_int),
.gmii_rxd(sfp2_gmii_rxd_int),
.gmii_rx_dv(sfp2_gmii_rx_dv_int),
.gmii_rx_er(sfp2_gmii_rx_er_int),
.gmii_isolate(),
.configuration_vector(sfp2_config_vect),
.status_vector(sfp2_status_vect),
.reset(rst_125mhz_int),
.signal_detect(1'b1)
);
wire sfp3_gmii_txuserclk2 = sfp0_gmii_txuserclk2;
wire sfp3_gmii_resetdone;
assign sfp3_gmii_clk_int = sfp3_gmii_txuserclk2;
taxi_sync_reset #(
.N(4)
)
sync_reset_sfp3_inst (
.clk(sfp3_gmii_clk_int),
.rst(rst_125mhz_int || !sfp3_gmii_resetdone),
.out(sfp3_gmii_rst_int)
);
wire sfp3_status_link_status = sfp3_status_vect[0];
wire sfp3_status_link_synchronization = sfp3_status_vect[1];
wire sfp3_status_rudi_c = sfp3_status_vect[2];
wire sfp3_status_rudi_i = sfp3_status_vect[3];
wire sfp3_status_rudi_invalid = sfp3_status_vect[4];
wire sfp3_status_rxdisperr = sfp3_status_vect[5];
wire sfp3_status_rxnotintable = sfp3_status_vect[6];
wire sfp3_status_phy_link_status = sfp3_status_vect[7];
wire [1:0] sfp3_status_remote_fault_encdg = sfp3_status_vect[9:8];
wire [1:0] sfp3_status_speed = sfp3_status_vect[11:10];
wire sfp3_status_duplex = sfp3_status_vect[12];
wire sfp3_status_remote_fault = sfp3_status_vect[13];
wire [1:0] sfp3_status_pause = sfp3_status_vect[15:14];
wire [4:0] sfp3_config_vect;
assign sfp3_config_vect[4] = 1'b0; // autonegotiation enable
assign sfp3_config_vect[3] = 1'b0; // isolate
assign sfp3_config_vect[2] = 1'b0; // power down
assign sfp3_config_vect[1] = 1'b0; // loopback enable
assign sfp3_config_vect[0] = 1'b0; // unidirectional enable
basex_pcs_pma_1
sfp3_pcspma (
.gtrefclk(sfp0_gmii_gtrefclk),
.txn(sfp_tx_n[3]),
.txp(sfp_tx_p[3]),
.rxn(sfp_rx_n[3]),
.rxp(sfp_rx_p[3]),
.independent_clock_bufg(clk_62mhz_int),
.txoutclk(),
.gtpowergood(),
.rxoutclk(),
.resetdone(sfp3_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(1'b0),
.rxuserclk2(1'b0),
.gmii_txd(sfp3_gmii_txd_int),
.gmii_tx_en(sfp3_gmii_tx_en_int),
.gmii_tx_er(sfp3_gmii_tx_er_int),
.gmii_rxd(sfp3_gmii_rxd_int),
.gmii_rx_dv(sfp3_gmii_rx_dv_int),
.gmii_rx_er(sfp3_gmii_rx_er_int),
.gmii_isolate(),
.configuration_vector(sfp3_config_vect),
.status_vector(sfp3_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
// SW12:2 (sw[2]) off for SFP0, on for SFP1
// SW12:4 (sw[0]) off for LSB of status vector, on for MSB
wire [15:0] sel_sv = sw[2] ? sfp1_status_vect : sfp0_status_vect;
assign led = sw[3] ? (sw[0] ? sel_sv[15:8] : sel_sv[7:0]) : led_int;
fpga_core #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.SFP_RATE(SFP_RATE)
.SFP_RATE(SFP_RATE),
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.MAC_DATA_W(MAC_DATA_W)
)
core_inst (
/*
@@ -613,7 +270,7 @@ core_inst (
.btnr(btnr_int),
.btnc(btnc_int),
.sw(sw_int),
.led(led_int),
.led(led),
/*
* UART: 115200 bps, 8N1
@@ -628,51 +285,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_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),
.sfp0_gmii_rxd(sfp0_gmii_rxd_int),
.sfp0_gmii_rx_dv(sfp0_gmii_rx_dv_int),
.sfp0_gmii_rx_er(sfp0_gmii_rx_er_int),
.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),
.sfp1_gmii_clk(sfp1_gmii_clk_int),
.sfp1_gmii_rst(sfp1_gmii_rst_int),
.sfp1_gmii_clk_en(sfp1_gmii_clk_en_int),
.sfp1_gmii_rxd(sfp1_gmii_rxd_int),
.sfp1_gmii_rx_dv(sfp1_gmii_rx_dv_int),
.sfp1_gmii_rx_er(sfp1_gmii_rx_er_int),
.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),
.sfp2_gmii_clk(sfp2_gmii_clk_int),
.sfp2_gmii_rst(sfp2_gmii_rst_int),
.sfp2_gmii_clk_en(sfp2_gmii_clk_en_int),
.sfp2_gmii_rxd(sfp2_gmii_rxd_int),
.sfp2_gmii_rx_dv(sfp2_gmii_rx_dv_int),
.sfp2_gmii_rx_er(sfp2_gmii_rx_er_int),
.sfp2_gmii_txd(sfp2_gmii_txd_int),
.sfp2_gmii_tx_en(sfp2_gmii_tx_en_int),
.sfp2_gmii_tx_er(sfp2_gmii_tx_er_int),
.sfp3_gmii_clk(sfp3_gmii_clk_int),
.sfp3_gmii_rst(sfp3_gmii_rst_int),
.sfp3_gmii_clk_en(sfp3_gmii_clk_en_int),
.sfp3_gmii_rxd(sfp3_gmii_rxd_int),
.sfp3_gmii_rx_dv(sfp3_gmii_rx_dv_int),
.sfp3_gmii_rx_er(sfp3_gmii_rx_er_int),
.sfp3_gmii_txd(sfp3_gmii_txd_int),
.sfp3_gmii_tx_en(sfp3_gmii_tx_en_int),
.sfp3_gmii_tx_er(sfp3_gmii_tx_er_int),
.sfp_tx_disable_b(sfp_tx_disable_b)
);

View File

@@ -24,7 +24,11 @@ module fpga_core #
// device family
parameter string FAMILY = "zynquplus",
// SFP rate selection (0 for 1G, 1 for 10G)
parameter logic SFP_RATE = 1'b1
parameter logic SFP_RATE = 1'b1,
// 10G MAC configuration
parameter logic CFG_LOW_LATENCY = 1'b1,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter MAC_DATA_W = 32
)
(
/*
@@ -63,46 +67,6 @@ module fpga_core #
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,
input wire logic [7:0] sfp0_gmii_rxd,
input wire logic sfp0_gmii_rx_dv,
input wire logic sfp0_gmii_rx_er,
output wire logic [7:0] sfp0_gmii_txd,
output wire logic sfp0_gmii_tx_en,
output wire logic sfp0_gmii_tx_er,
input wire logic sfp1_gmii_clk,
input wire logic sfp1_gmii_rst,
input wire logic sfp1_gmii_clk_en,
input wire logic [7:0] sfp1_gmii_rxd,
input wire logic sfp1_gmii_rx_dv,
input wire logic sfp1_gmii_rx_er,
output wire logic [7:0] sfp1_gmii_txd,
output wire logic sfp1_gmii_tx_en,
output wire logic sfp1_gmii_tx_er,
input wire logic sfp2_gmii_clk,
input wire logic sfp2_gmii_rst,
input wire logic sfp2_gmii_clk_en,
input wire logic [7:0] sfp2_gmii_rxd,
input wire logic sfp2_gmii_rx_dv,
input wire logic sfp2_gmii_rx_er,
output wire logic [7:0] sfp2_gmii_txd,
output wire logic sfp2_gmii_tx_en,
output wire logic sfp2_gmii_tx_er,
input wire logic sfp3_gmii_clk,
input wire logic sfp3_gmii_rst,
input wire logic sfp3_gmii_clk_en,
input wire logic [7:0] sfp3_gmii_rxd,
input wire logic sfp3_gmii_rx_dv,
input wire logic sfp3_gmii_rx_er,
output wire logic [7:0] sfp3_gmii_txd,
output wire logic sfp3_gmii_tx_en,
output wire logic sfp3_gmii_tx_er,
output wire logic [3:0] sfp_tx_disable_b
);
@@ -139,7 +103,7 @@ xfcp_if_uart_inst (
.prescale(16'(125000000/2000000))
);
localparam XFCP_PORTS = SFP_RATE ? 2 : 1;
localparam XFCP_PORTS = 2;
taxi_axis_if #(.DATA_W(8), .USER_EN(1), .USER_W(1)) xfcp_sw_ds[XFCP_PORTS](), xfcp_sw_us[XFCP_PORTS]();
@@ -191,7 +155,7 @@ xfcp_stats_inst (
.s_axis_stat(axis_stat)
);
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(10)) axis_eth_stat[SFP_RATE ? 1 : 4]();
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(10)) axis_eth_stat[2]();
taxi_axis_arb_mux #(
.S_COUNT($size(axis_eth_stat)),
@@ -217,69 +181,219 @@ stat_mux_inst (
// SFP+
assign sfp_tx_disable_b = '1;
wire sfp_tx_clk[4];
wire sfp_tx_rst[4];
wire sfp_rx_clk[4];
wire sfp_rx_rst[4];
wire sfp_rx_status[4];
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(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_tx[4]();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[4]();
taxi_axis_if #(.DATA_W(MAC_DATA_W), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_rx[4]();
if (SIM) begin
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_GTE4 ibufds_gte4_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_125mhz),
.out(sfp_rst)
);
taxi_apb_if #(
.ADDR_W(18),
.DATA_W(16)
)
gt_apb_ctrl();
taxi_xfcp_mod_apb #(
.XFCP_EXT_ID_STR("GTH CTRL")
)
xfcp_mod_apb_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* XFCP upstream port
*/
.xfcp_usp_ds(xfcp_sw_ds[1]),
.xfcp_usp_us(xfcp_sw_us[1]),
/*
* APB master interface
*/
.m_apb(gt_apb_ctrl)
);
if (SFP_RATE == 0) begin : sfp_mac
taxi_axis_if #(.DATA_W(8), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp0_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp0_tx_cpl();
taxi_eth_mac_1g_basex_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
taxi_axis_if #(.DATA_W(8), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp1_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp1_tx_cpl();
.CNT(4),
taxi_axis_if #(.DATA_W(8), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp2_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp2_tx_cpl();
// GT config
.CFG_LOW_LATENCY(CFG_LOW_LATENCY),
taxi_axis_if #(.DATA_W(8), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp3_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp3_tx_cpl();
// GT type
.GT_TYPE("GTH"),
taxi_eth_mac_1g_fifo #(
// PHY parameters
.COMBINED_MAC_PCS(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),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE((16+16)*0),
.STAT_ID_BASE(0),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(1),
.STAT_PREFIX_STR("SFP0"),
.TX_FIFO_DEPTH(16384),
.TX_FRAME_FIFO(1),
.RX_FIFO_DEPTH(16384),
.RX_FRAME_FIFO(1)
.STAT_PREFIX_STR('{"SFP0", "SFP1", "SFP2", "SFP3"})
)
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_125mhz),
.logic_rst(rst_125mhz),
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_0),
.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_0),
.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('{4{1'b0}}),
.rx_rst_out(sfp_rx_rst),
.tx_clk(sfp_tx_clk),
.tx_rst_in('{4{1'b0}}),
.tx_rst_out(sfp_tx_rst),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(axis_sfp0_eth),
.m_axis_tx_cpl(axis_sfp0_tx_cpl),
.s_axis_tx(axis_sfp_tx),
.m_axis_tx_cpl(axis_sfp_tx_cpl),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(axis_sfp0_eth),
.m_axis_rx(axis_sfp_rx),
/*
* GMII interface
* PTP clock
*/
.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),
.ptp_clk(1'b0),
.ptp_rst(1'b0),
.ptp_sample_clk(1'b0),
.ptp_td_sdi(1'b0),
.tx_ptp_ts_in('{4{'0}}),
.tx_ptp_ts_out(),
.tx_ptp_ts_step_out(),
.tx_ptp_locked(),
.rx_ptp_ts_in('{4{'0}}),
.rx_ptp_ts_out(),
.rx_ptp_ts_step_out(),
.rx_ptp_locked(),
/*
* Control
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
*/
.rx_clk_enable(sfp0_gmii_clk_en),
.tx_clk_enable(sfp0_gmii_clk_en),
.rx_mii_select(1'b0),
.tx_mii_select(1'b0),
.tx_lfc_req('{4{1'b0}}),
.tx_lfc_resend('{4{1'b0}}),
.rx_lfc_en('{4{1'b0}}),
.rx_lfc_req(),
.rx_lfc_ack('{4{1'b0}}),
/*
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
*/
.tx_pfc_req('{4{'0}}),
.tx_pfc_resend('{4{1'b0}}),
.rx_pfc_en('{4{'0}}),
.rx_pfc_req(),
.rx_pfc_ack('{4{'0}}),
/*
* Pause interface
*/
.tx_lfc_pause_en('{4{1'b0}}),
.tx_pause_req('{4{1'b0}}),
.tx_pause_ack(),
/*
* Statistics
@@ -291,357 +405,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('{4{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)
);
taxi_eth_mac_1g_fifo #(
.STAT_EN(1),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE((16+16)*1),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(1),
.STAT_PREFIX_STR("SFP1"),
.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_125mhz),
.logic_rst(rst_125mhz),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(axis_sfp1_eth),
.m_axis_tx_cpl(axis_sfp1_tx_cpl),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(axis_sfp1_eth),
/*
* 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),
/*
* 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),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[1]),
/*
* 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_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)
);
taxi_eth_mac_1g_fifo #(
.STAT_EN(1),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE((16+16)*2),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(1),
.STAT_PREFIX_STR("SFP2"),
.TX_FIFO_DEPTH(16384),
.TX_FRAME_FIFO(1),
.RX_FIFO_DEPTH(16384),
.RX_FRAME_FIFO(1)
)
sfp2_eth_mac_inst (
.rx_clk(sfp2_gmii_clk),
.rx_rst(sfp2_gmii_rst),
.tx_clk(sfp2_gmii_clk),
.tx_rst(sfp2_gmii_rst),
.logic_clk(clk_125mhz),
.logic_rst(rst_125mhz),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(axis_sfp2_eth),
.m_axis_tx_cpl(axis_sfp2_tx_cpl),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(axis_sfp2_eth),
/*
* GMII interface
*/
.gmii_rxd(sfp2_gmii_rxd),
.gmii_rx_dv(sfp2_gmii_rx_dv),
.gmii_rx_er(sfp2_gmii_rx_er),
.gmii_txd(sfp2_gmii_txd),
.gmii_tx_en(sfp2_gmii_tx_en),
.gmii_tx_er(sfp2_gmii_tx_er),
/*
* Control
*/
.rx_clk_enable(sfp2_gmii_clk_en),
.tx_clk_enable(sfp2_gmii_clk_en),
.rx_mii_select(1'b0),
.tx_mii_select(1'b0),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[2]),
/*
* 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_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)
);
taxi_eth_mac_1g_fifo #(
.STAT_EN(1),
.STAT_TX_LEVEL(1),
.STAT_RX_LEVEL(1),
.STAT_ID_BASE((16+16)*3),
.STAT_UPDATE_PERIOD(1024),
.STAT_STR_EN(1),
.STAT_PREFIX_STR("SFP3"),
.TX_FIFO_DEPTH(16384),
.TX_FRAME_FIFO(1),
.RX_FIFO_DEPTH(16384),
.RX_FRAME_FIFO(1)
)
sfp3_eth_mac_inst (
.rx_clk(sfp3_gmii_clk),
.rx_rst(sfp3_gmii_rst),
.tx_clk(sfp3_gmii_clk),
.tx_rst(sfp3_gmii_rst),
.logic_clk(clk_125mhz),
.logic_rst(rst_125mhz),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(axis_sfp3_eth),
.m_axis_tx_cpl(axis_sfp3_tx_cpl),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(axis_sfp3_eth),
/*
* GMII interface
*/
.gmii_rxd(sfp3_gmii_rxd),
.gmii_rx_dv(sfp3_gmii_rx_dv),
.gmii_rx_er(sfp3_gmii_rx_er),
.gmii_txd(sfp3_gmii_txd),
.gmii_tx_en(sfp3_gmii_tx_en),
.gmii_tx_er(sfp3_gmii_tx_er),
/*
* Control
*/
.rx_clk_enable(sfp3_gmii_clk_en),
.tx_clk_enable(sfp3_gmii_clk_en),
.rx_mii_select(1'b0),
.tx_mii_select(1'b0),
/*
* Statistics
*/
.stat_clk(clk_125mhz),
.stat_rst(rst_125mhz),
.m_axis_stat(axis_eth_stat[3]),
/*
* 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_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('{4{1'b1}}),
.cfg_tx_min_pkt_len('{4{8'd60-1}}),
.cfg_tx_max_pkt_len('{4{16'd9218-1}}),
.cfg_tx_ifg('{4{8'd12}}),
.cfg_tx_enable('{4{1'b1}}),
.cfg_rx_max_pkt_len('{4{16'd9218-1}}),
.cfg_rx_enable('{4{1'b1}}),
.cfg_tx_prbs31_enable('{4{1'b0}}),
.cfg_rx_prbs31_enable('{4{1'b0}}),
.cfg_mcf_rx_eth_dst_mcast('{4{48'h01_80_C2_00_00_01}}),
.cfg_mcf_rx_check_eth_dst_mcast('{4{1'b1}}),
.cfg_mcf_rx_eth_dst_ucast('{4{48'd0}}),
.cfg_mcf_rx_check_eth_dst_ucast('{4{1'b0}}),
.cfg_mcf_rx_eth_src('{4{48'd0}}),
.cfg_mcf_rx_check_eth_src('{4{1'b0}}),
.cfg_mcf_rx_eth_type('{4{16'h8808}}),
.cfg_mcf_rx_opcode_lfc('{4{16'h0001}}),
.cfg_mcf_rx_check_opcode_lfc('{4{1'b1}}),
.cfg_mcf_rx_opcode_pfc('{4{16'h0101}}),
.cfg_mcf_rx_check_opcode_pfc('{4{1'b1}}),
.cfg_mcf_rx_forward('{4{1'b0}}),
.cfg_mcf_rx_enable('{4{1'b0}}),
.cfg_tx_lfc_eth_dst('{4{48'h01_80_C2_00_00_01}}),
.cfg_tx_lfc_eth_src('{4{48'h80_23_31_43_54_4C}}),
.cfg_tx_lfc_eth_type('{4{16'h8808}}),
.cfg_tx_lfc_opcode('{4{16'h0001}}),
.cfg_tx_lfc_en('{4{1'b0}}),
.cfg_tx_lfc_quanta('{4{16'hffff}}),
.cfg_tx_lfc_refresh('{4{16'h7fff}}),
.cfg_tx_pfc_eth_dst('{4{48'h01_80_C2_00_00_01}}),
.cfg_tx_pfc_eth_src('{4{48'h80_23_31_43_54_4C}}),
.cfg_tx_pfc_eth_type('{4{16'h8808}}),
.cfg_tx_pfc_opcode('{4{16'h0101}}),
.cfg_tx_pfc_en('{4{1'b0}}),
.cfg_tx_pfc_quanta('{4{'{8{16'hffff}}}}),
.cfg_tx_pfc_refresh('{4{'{8{16'h7fff}}}}),
.cfg_rx_lfc_opcode('{4{16'h0001}}),
.cfg_rx_lfc_en('{4{1'b0}}),
.cfg_rx_pfc_opcode('{4{16'h0101}}),
.cfg_rx_pfc_en('{4{1'b0}})
);
end else begin : sfp_mac
wire sfp_tx_clk[4];
wire sfp_tx_rst[4];
wire sfp_rx_clk[4];
wire sfp_rx_rst[4];
wire sfp_rx_status[4];
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(32), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_tx[4]();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[4]();
taxi_axis_if #(.DATA_W(32), .ID_W(8), .USER_EN(1), .USER_W(1)) axis_sfp_rx[4]();
if (SIM) begin
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_GTE4 ibufds_gte4_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_125mhz),
.out(sfp_rst)
);
taxi_apb_if #(
.ADDR_W(18),
.DATA_W(16)
)
gt_apb_ctrl();
taxi_xfcp_mod_apb #(
.XFCP_EXT_ID_STR("GTH CTRL")
)
xfcp_mod_apb_inst (
.clk(clk_125mhz),
.rst(rst_125mhz),
/*
* XFCP upstream port
*/
.xfcp_usp_ds(xfcp_sw_ds[1]),
.xfcp_usp_us(xfcp_sw_us[1]),
/*
* APB master interface
*/
.m_apb(gt_apb_ctrl)
);
taxi_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
@@ -650,12 +513,13 @@ end else begin : sfp_mac
.CNT(4),
// 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),
.DIC_EN(1'b1),
.PTP_TS_EN(1'b0),
@@ -881,57 +745,57 @@ end else begin : sfp_mac
.cfg_rx_pfc_en('{4{1'b0}})
);
for (genvar n = 0; n < 4; n = n + 1) begin : sfp_ch
end
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]),
for (genvar n = 0; n < $size(axis_sfp_tx); n = n + 1) begin : sfp_ch
/*
* AXI4-Stream output (source)
*/
.m_clk(sfp_tx_clk[n]),
.m_rst(sfp_tx_rst[n]),
.m_axis(axis_sfp_tx[n]),
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]),
/*
* Pause
*/
.s_pause_req(1'b0),
.s_pause_ack(),
.m_pause_req(1'b0),
.m_pause_ack(),
/*
* AXI4-Stream output (source)
*/
.m_clk(sfp_tx_clk[n]),
.m_rst(sfp_tx_rst[n]),
.m_axis(axis_sfp_tx[n]),
/*
* 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()
);
/*
* Pause
*/
.s_pause_req(1'b0),
.s_pause_ack(),
.m_pause_req(1'b0),
.m_pause_ack(),
end
/*
* 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

View File

@@ -25,6 +25,7 @@ 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)/xfcp/rtl/taxi_xfcp_if_uart.f
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_switch.sv
VERILOG_SOURCES += $(TAXI_SRC_DIR)/xfcp/rtl/taxi_xfcp_mod_apb.f
@@ -44,6 +45,9 @@ export PARAM_SIM := "1'b1"
export PARAM_VENDOR := "\"XILINX\""
export PARAM_FAMILY := "\"zynquplus\""
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

View File

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

View File

@@ -20,17 +20,19 @@ import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Combine
from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink
from cocotbext.eth import GmiiSource, GmiiSink
from cocotbext.eth import XgmiiFrame
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]
@@ -47,43 +49,55 @@ class TB:
self.sfp_sources = []
self.sfp_sinks = []
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())
cocotb.start_soon(Clock(dut.sfp2_gmii_clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.sfp3_gmii_clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.sfp_mgt_refclk_0_p, 6.4, 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))
self.sfp_sources.append(GmiiSource(dut.sfp2_gmii_rxd, dut.sfp2_gmii_rx_er, dut.sfp2_gmii_rx_dv,
dut.sfp2_gmii_clk, dut.sfp2_gmii_rst, dut.sfp2_gmii_clk_en))
self.sfp_sinks.append(GmiiSink(dut.sfp2_gmii_txd, dut.sfp2_gmii_tx_er, dut.sfp2_gmii_tx_en,
dut.sfp2_gmii_clk, dut.sfp2_gmii_rst, dut.sfp2_gmii_clk_en))
self.sfp_sources.append(GmiiSource(dut.sfp3_gmii_rxd, dut.sfp3_gmii_rx_er, dut.sfp3_gmii_rx_dv,
dut.sfp3_gmii_clk, dut.sfp3_gmii_rst, dut.sfp3_gmii_clk_en))
self.sfp_sinks.append(GmiiSink(dut.sfp3_gmii_txd, dut.sfp3_gmii_tx_er, dut.sfp3_gmii_tx_en,
dut.sfp3_gmii_clk, dut.sfp3_gmii_rst, dut.sfp3_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:
gt_inst = ch.ch_inst.gt.gt_inst
for ch in dut.sfp_mac.sfp_mac_inst.ch:
gt_inst = ch.ch_inst.gt.gt_inst
if dut.SFP_RATE.value == 0:
if ch.ch_inst.CFG_LOW_LATENCY.value:
clk = 3.102
gbx_cfg = (66, [64, 65])
else:
clk = 3.2
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:
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())
@@ -123,28 +137,16 @@ class TB:
async def init(self):
self.dut.rst_125mhz.setimmediatevalue(0)
self.dut.sfp0_gmii_rst.setimmediatevalue(0)
self.dut.sfp1_gmii_rst.setimmediatevalue(0)
self.dut.sfp2_gmii_rst.setimmediatevalue(0)
self.dut.sfp3_gmii_rst.setimmediatevalue(0)
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
self.dut.rst_125mhz.value = 1
self.dut.sfp0_gmii_rst.value = 1
self.dut.sfp1_gmii_rst.value = 1
self.dut.sfp2_gmii_rst.value = 1
self.dut.sfp3_gmii_rst.value = 1
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
self.dut.rst_125mhz.value = 0
self.dut.sfp0_gmii_rst.value = 0
self.dut.sfp1_gmii_rst.value = 0
self.dut.sfp2_gmii_rst.value = 0
self.dut.sfp3_gmii_rst.value = 0
for k in range(10):
await RisingEdge(self.dut.clk_125mhz)
@@ -153,51 +155,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_125mhz)
sink.clear()
tb.log.info("Multiple small packets")
@@ -245,13 +203,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)):
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_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)
@@ -280,8 +238,8 @@ 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(("sfp_rate", "mac_data_w"), [(0, 16), (1, 32), (1, 64)])
def test_fpga_core(request, sfp_rate, mac_data_w):
dut = "fpga_core"
module = os.path.splitext(os.path.basename(__file__))[0]
toplevel = dut
@@ -290,6 +248,7 @@ def test_fpga_core(request, sfp_rate):
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, "xfcp", "rtl", "taxi_xfcp_if_uart.f"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_switch.sv"),
os.path.join(taxi_src_dir, "xfcp", "rtl", "taxi_xfcp_mod_apb.f"),
@@ -307,6 +266,9 @@ def test_fpga_core(request, sfp_rate):
parameters['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"zynquplus\""
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()}