example/KR260: Add support for 10GBASE-R on KR260

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2025-02-22 23:01:52 -08:00
parent db8b1fc27e
commit 4a439783f1
10 changed files with 633 additions and 144 deletions

View File

@@ -10,12 +10,14 @@ The design places looped-back MACs on the BASE-T ports and SFP+ cage.
* Looped-back MAC via RGMII * Looped-back MAC via RGMII
* SFP+ cage * SFP+ cage
* Looped-back 1000BASE-X via Xilinx PCS/PMA core and GTH transceiver * Looped-back 1000BASE-X via Xilinx PCS/PMA core and GTH transceiver
* Looped-back 10GBASE-R MAC via GTH transceiver
## Board details ## Board details
* FPGA: xck26-sfvc784-2LV-c * FPGA: xck26-sfvc784-2LV-c
* 1000BASE-T PHY: TI DP83867CSRGZ via RGMII * 1000BASE-T PHY: TI DP83867CSRGZ via RGMII
* 1000BASE-X PHY: Xilinx PCS/PMA core via GTH transceiver * 1000BASE-X PHY: Xilinx PCS/PMA core via GTH transceiver
* 10GBASE-R PHY: Soft PCS with GTH transceiver
## Licensing ## Licensing

View File

@@ -0,0 +1,48 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xck26-sfvc784-2LV-c
FPGA_TOP = fpga
FPGA_ARCH = zynquplus
# Files for synthesis
SYN_FILES = ../rtl/fpga.sv
SYN_FILES += ../rtl/fpga_core.sv
SYN_FILES += ../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us.f
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_rgmii_fifo.f
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_reset.sv
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_signal.sv
# XDC files
XDC_FILES = ../fpga.xdc
XDC_FILES += ../eth_rgmii.xdc
XDC_FILES += ../lib/taxi/syn/vivado/taxi_rgmii_phy_if.tcl
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_1g_rgmii.tcl
XDC_FILES += ../lib/taxi/syn/vivado/taxi_eth_mac_fifo.tcl
XDC_FILES += ../lib/taxi/syn/vivado/taxi_axis_async_fifo.tcl
XDC_FILES += ../lib/taxi/syn/vivado/taxi_sync_reset.tcl
# IP
IP_TCL_FILES = ../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us_gth_10g_156.tcl
# Configuration
CONFIG_TCL_FILES = ./config.tcl
include ../common/vivado.mk
program: $(PROJECT).bit
echo "open_hw_manager" > program.tcl
echo "connect_hw_server" >> program.tcl
echo "open_hw_target" >> program.tcl
echo "current_hw_device [lindex [get_hw_devices] 0]" >> program.tcl
echo "refresh_hw_device -update_hw_probes false [current_hw_device]" >> program.tcl
echo "set_property PROGRAM.FILE {$(PROJECT).bit} [current_hw_device]" >> program.tcl
echo "program_hw_devices [current_hw_device]" >> program.tcl
echo "exit" >> program.tcl
vivado -nojournal -nolog -mode batch -source program.tcl

View File

@@ -0,0 +1,21 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# SFP+ rate
# 0 for 1G, 1 for 10G
dict set params SFP_RATE "1"
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -32,7 +32,7 @@ XDC_FILES += ../lib/taxi/syn/vivado/taxi_sync_reset.tcl
IP_TCL_FILES = ../ip/basex_pcs_pma_0.tcl IP_TCL_FILES = ../ip/basex_pcs_pma_0.tcl
# Configuration # Configuration
# CONFIG_TCL_FILES = ./config.tcl CONFIG_TCL_FILES = ./config.tcl
include ../common/vivado.mk include ../common/vivado.mk

View File

@@ -0,0 +1,21 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
set params [dict create]
# SFP+ rate
# 0 for 1G, 1 for 10G
dict set params SFP_RATE "0"
# apply parameters to top-level
set param_list {}
dict for {name value} $params {
lappend param_list $name=$value
}
set_property generic $param_list [get_filesets sources_1]

View File

@@ -24,7 +24,9 @@ module fpga #
// device family // device family
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)
parameter logic SFP_RATE = 1'b1
) )
( (
/* /*
@@ -386,10 +388,13 @@ phy3_rx_ctl_idelay (
.CNTVALUEOUT() .CNTVALUEOUT()
); );
// 1000BASE-X SFP // SFP
wire sfp_tx_p_int;
wire sfp_tx_n_int;
wire sfp_gmii_clk_int; wire sfp_gmii_clk_int;
wire sfp_gmii_rst_int; wire sfp_gmii_rst_int;
wire sfp_gmii_clk_en_int; wire sfp_gmii_clk_en_int = 1'b1;
wire [7:0] sfp_gmii_txd_int; wire [7:0] sfp_gmii_txd_int;
wire sfp_gmii_tx_en_int; wire sfp_gmii_tx_en_int;
wire sfp_gmii_tx_er_int; wire sfp_gmii_tx_er_int;
@@ -397,46 +402,49 @@ wire [7:0] sfp_gmii_rxd_int;
wire sfp_gmii_rx_dv_int; wire sfp_gmii_rx_dv_int;
wire sfp_gmii_rx_er_int; wire sfp_gmii_rx_er_int;
wire sfp_gmii_txuserclk2; if (SFP_RATE == 0) begin : sfp_phy
wire sfp_gmii_resetdone; // 1000BASE-X
assign sfp_gmii_clk_int = sfp_gmii_txuserclk2; wire sfp_gmii_txuserclk2;
wire sfp_gmii_resetdone;
taxi_sync_reset #( assign sfp_gmii_clk_int = sfp_gmii_txuserclk2;
taxi_sync_reset #(
.N(4) .N(4)
) )
sync_reset_sfp_inst ( sync_reset_sfp_inst (
.clk(sfp_gmii_clk_int), .clk(sfp_gmii_clk_int),
.rst(rst_125mhz_int || !sfp_gmii_resetdone), .rst(rst_125mhz_int || !sfp_gmii_resetdone),
.out(sfp_gmii_rst_int) .out(sfp_gmii_rst_int)
); );
wire [15:0] sfp_status_vect; wire [15:0] sfp_status_vect;
wire sfp_status_link_status = sfp_status_vect[0]; wire sfp_status_link_status = sfp_status_vect[0];
wire sfp_status_link_synchronization = sfp_status_vect[1]; wire sfp_status_link_synchronization = sfp_status_vect[1];
wire sfp_status_rudi_c = sfp_status_vect[2]; wire sfp_status_rudi_c = sfp_status_vect[2];
wire sfp_status_rudi_i = sfp_status_vect[3]; wire sfp_status_rudi_i = sfp_status_vect[3];
wire sfp_status_rudi_invalid = sfp_status_vect[4]; wire sfp_status_rudi_invalid = sfp_status_vect[4];
wire sfp_status_rxdisperr = sfp_status_vect[5]; wire sfp_status_rxdisperr = sfp_status_vect[5];
wire sfp_status_rxnotintable = sfp_status_vect[6]; wire sfp_status_rxnotintable = sfp_status_vect[6];
wire sfp_status_phy_link_status = sfp_status_vect[7]; 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_remote_fault_encdg = sfp_status_vect[9:8];
wire [1:0] sfp_status_speed = sfp_status_vect[11:10]; wire [1:0] sfp_status_speed = sfp_status_vect[11:10];
wire sfp_status_duplex = sfp_status_vect[12]; wire sfp_status_duplex = sfp_status_vect[12];
wire sfp_status_remote_fault = sfp_status_vect[13]; wire sfp_status_remote_fault = sfp_status_vect[13];
wire [1:0] sfp_status_pause = sfp_status_vect[15:14]; wire [1:0] sfp_status_pause = sfp_status_vect[15:14];
wire [4:0] sfp_config_vect; wire [4:0] sfp_config_vect;
assign sfp_config_vect[4] = 1'b0; // autonegotiation enable assign sfp_config_vect[4] = 1'b0; // autonegotiation enable
assign sfp_config_vect[3] = 1'b0; // isolate assign sfp_config_vect[3] = 1'b0; // isolate
assign sfp_config_vect[2] = 1'b0; // power down assign sfp_config_vect[2] = 1'b0; // power down
assign sfp_config_vect[1] = 1'b0; // loopback enable assign sfp_config_vect[1] = 1'b0; // loopback enable
assign sfp_config_vect[0] = 1'b0; // unidirectional enable assign sfp_config_vect[0] = 1'b0; // unidirectional enable
basex_pcs_pma_0 basex_pcs_pma_0
sfp_pcspma ( sfp_pcspma (
.gtrefclk_p(sfp_mgt_refclk_p), .gtrefclk_p(sfp_mgt_refclk_p),
.gtrefclk_n(sfp_mgt_refclk_n), .gtrefclk_n(sfp_mgt_refclk_n),
.gtrefclk_out(), .gtrefclk_out(),
@@ -464,15 +472,22 @@ sfp_pcspma (
.status_vector(sfp_status_vect), .status_vector(sfp_status_vect),
.reset(rst_125mhz_int), .reset(rst_125mhz_int),
.signal_detect(1'b1) .signal_detect(1'b1)
); );
assign sfp_gmii_clk_en_int = 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)
) )
core_inst ( core_inst (
/* /*
@@ -509,8 +524,15 @@ core_inst (
.phy3_reset_n(phy3_reset_n), .phy3_reset_n(phy3_reset_n),
/* /*
* Ethernet: 1000BASE-X SFP * Ethernet: SFP+
*/ */
.sfp_rx_p(sfp_rx_p),
.sfp_rx_n(sfp_rx_n),
.sfp_tx_p(sfp_tx_p_int),
.sfp_tx_n(sfp_tx_n_int),
.sfp_mgt_refclk_p(sfp_mgt_refclk_p),
.sfp_mgt_refclk_n(sfp_mgt_refclk_n),
.sfp_gmii_clk(sfp_gmii_clk_int), .sfp_gmii_clk(sfp_gmii_clk_int),
.sfp_gmii_rst(sfp_gmii_rst_int), .sfp_gmii_rst(sfp_gmii_rst_int),
.sfp_gmii_clk_en(sfp_gmii_clk_en_int), .sfp_gmii_clk_en(sfp_gmii_clk_en_int),
@@ -520,10 +542,12 @@ core_inst (
.sfp_gmii_txd(sfp_gmii_txd_int), .sfp_gmii_txd(sfp_gmii_txd_int),
.sfp_gmii_tx_en(sfp_gmii_tx_en_int), .sfp_gmii_tx_en(sfp_gmii_tx_en_int),
.sfp_gmii_tx_er(sfp_gmii_tx_er_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),
.sfp_mod_abs(sfp_mod_abs_int), .sfp_mod_abs(sfp_mod_abs_int),
.sfp_i2c_scl_i(sfp_i2c_scl_i), .sfp_i2c_scl_i(sfp_i2c_scl_i),
.sfp_i2c_scl_o(sfp_i2c_scl_o), .sfp_i2c_scl_o(sfp_i2c_scl_o),
.sfp_i2c_scl_t(sfp_i2c_scl_t), .sfp_i2c_scl_t(sfp_i2c_scl_t),

View File

@@ -24,7 +24,9 @@ module fpga_core #
// device family // device family
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)
parameter logic SFP_RATE = 1'b1
) )
( (
/* /*
@@ -61,8 +63,15 @@ module fpga_core #
output wire logic phy3_reset_n, output wire logic phy3_reset_n,
/* /*
* Ethernet: 1000BASE-X SFP * Ethernet: SFP+
*/ */
input wire logic sfp_rx_p,
input wire logic sfp_rx_n,
output wire logic sfp_tx_p,
output wire logic sfp_tx_n,
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_clk,
input wire logic sfp_gmii_rst, input wire logic sfp_gmii_rst,
input wire logic sfp_gmii_clk_en, input wire logic sfp_gmii_clk_en,
@@ -77,6 +86,7 @@ module fpga_core #
input wire logic sfp_tx_fault, input wire logic sfp_tx_fault,
input wire logic sfp_rx_los, input wire logic sfp_rx_los,
input wire logic sfp_mod_abs, input wire logic sfp_mod_abs,
input wire logic sfp_i2c_scl_i, input wire logic sfp_i2c_scl_i,
output wire logic sfp_i2c_scl_o, output wire logic sfp_i2c_scl_o,
output wire logic sfp_i2c_scl_t, output wire logic sfp_i2c_scl_t,
@@ -222,18 +232,20 @@ phy3_eth_mac_inst (
// SFP+ // SFP+
assign sfp_tx_disable = 1'b0; assign sfp_tx_disable = 1'b0;
taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp_eth(); if (SFP_RATE == 0) begin : sfp_mac
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl();
taxi_eth_mac_1g_fifo #( taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl();
taxi_eth_mac_1g_fifo #(
.PADDING_EN(1), .PADDING_EN(1),
.MIN_FRAME_LEN(64), .MIN_FRAME_LEN(64),
.TX_FIFO_DEPTH(16384), .TX_FIFO_DEPTH(16384),
.TX_FRAME_FIFO(1), .TX_FRAME_FIFO(1),
.RX_FIFO_DEPTH(16384), .RX_FIFO_DEPTH(16384),
.RX_FRAME_FIFO(1) .RX_FRAME_FIFO(1)
) )
sfp_eth_mac_inst ( sfp_eth_mac_inst (
.rx_clk(sfp_gmii_clk), .rx_clk(sfp_gmii_clk),
.rx_rst(sfp_gmii_rst), .rx_rst(sfp_gmii_rst),
.tx_clk(sfp_gmii_clk), .tx_clk(sfp_gmii_clk),
@@ -289,7 +301,290 @@ sfp_eth_mac_inst (
.cfg_ifg(8'd12), .cfg_ifg(8'd12),
.cfg_tx_enable(1'b1), .cfg_tx_enable(1'b1),
.cfg_rx_enable(1'b1) .cfg_rx_enable(1'b1)
); );
end else begin : sfp_mac
wire sfp_tx_clk;
wire sfp_tx_rst;
wire sfp_rx_clk;
wire sfp_rx_rst;
wire sfp_rx_status;
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(64), .ID_W(8)) axis_sfp_tx[0:0]();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[0:0]();
taxi_axis_if #(.DATA_W(64), .ID_W(8)) axis_sfp_rx[0:0]();
if (SIM) begin
assign sfp_gtpowergood = 1'b1;
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_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.CNT(1),
// GT type
.GT_TYPE("GTH"),
// PHY parameters
.PADDING_EN(1'b1),
.DIC_EN(1'b1),
.MIN_FRAME_LEN(64),
.PTP_TS_EN(1'b0),
.PTP_TS_FMT_TOD(1'b1),
.PTP_TS_W(96),
.PRBS31_EN(1'b0),
.TX_SERDES_PIPELINE(1),
.RX_SERDES_PIPELINE(1),
.COUNT_125US(125000/6.4)
)
sfp_mac_inst (
.xcvr_ctrl_clk(clk),
.xcvr_ctrl_rst(sfp_rst),
/*
* Common
*/
.xcvr_gtpowergood_out(sfp_gtpowergood),
.xcvr_gtrefclk00_in(sfp_mgt_refclk),
.xcvr_qpll0lock_out(),
.xcvr_qpll0clk_out(),
.xcvr_qpll0refclk_out(),
/*
* Serial data
*/
.xcvr_txp(sfp_tx_p),
.xcvr_txn(sfp_tx_n),
.xcvr_rxp(sfp_rx_p),
.xcvr_rxn(sfp_rx_n),
/*
* MAC clocks
*/
.rx_clk(sfp_rx_clk),
.rx_rst_in('0),
.rx_rst_out(sfp_rx_rst),
.tx_clk(sfp_tx_clk),
.tx_rst_in('0),
.tx_rst_out(sfp_tx_rst),
.ptp_sample_clk('0),
/*
* Transmit interface (AXI stream)
*/
.s_axis_tx(axis_sfp_tx),
.m_axis_tx_cpl(axis_sfp_tx_cpl),
/*
* Receive interface (AXI stream)
*/
.m_axis_rx(axis_sfp_rx),
/*
* PTP clock
*/
.tx_ptp_ts('0),
.tx_ptp_ts_step('0),
.rx_ptp_ts('0),
.rx_ptp_ts_step('0),
/*
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
*/
.tx_lfc_req('0),
.tx_lfc_resend('0),
.rx_lfc_en('0),
.rx_lfc_req(),
.rx_lfc_ack('0),
/*
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
*/
.tx_pfc_req('0),
.tx_pfc_resend('0),
.rx_pfc_en('0),
.rx_pfc_req(),
.rx_pfc_ack('0),
/*
* Pause interface
*/
.tx_lfc_pause_en('0),
.tx_pause_req('0),
.tx_pause_ack(),
/*
* Status
*/
.tx_start_packet(),
.tx_error_underflow(),
.rx_start_packet(),
.rx_error_count(),
.rx_error_bad_frame(),
.rx_error_bad_fcs(),
.rx_bad_block(),
.rx_sequence_error(),
.rx_block_lock(),
.rx_high_ber(),
.rx_status(sfp_rx_status),
.stat_tx_mcf(),
.stat_rx_mcf(),
.stat_tx_lfc_pkt(),
.stat_tx_lfc_xon(),
.stat_tx_lfc_xoff(),
.stat_tx_lfc_paused(),
.stat_tx_pfc_pkt(),
.stat_tx_pfc_xon(),
.stat_tx_pfc_xoff(),
.stat_tx_pfc_paused(),
.stat_rx_lfc_pkt(),
.stat_rx_lfc_xon(),
.stat_rx_lfc_xoff(),
.stat_rx_lfc_paused(),
.stat_rx_pfc_pkt(),
.stat_rx_pfc_xon(),
.stat_rx_pfc_xoff(),
.stat_rx_pfc_paused(),
/*
* Configuration
*/
.cfg_ifg('{1{8'd12}}),
.cfg_tx_enable('1),
.cfg_rx_enable('1),
.cfg_tx_prbs31_enable('0),
.cfg_rx_prbs31_enable('0),
.cfg_mcf_rx_eth_dst_mcast('{1{48'h01_80_C2_00_00_01}}),
.cfg_mcf_rx_check_eth_dst_mcast('1),
.cfg_mcf_rx_eth_dst_ucast('{1{48'd0}}),
.cfg_mcf_rx_check_eth_dst_ucast('0),
.cfg_mcf_rx_eth_src('{1{48'd0}}),
.cfg_mcf_rx_check_eth_src('0),
.cfg_mcf_rx_eth_type('{1{16'h8808}}),
.cfg_mcf_rx_opcode_lfc('{1{16'h0001}}),
.cfg_mcf_rx_check_opcode_lfc('1),
.cfg_mcf_rx_opcode_pfc('{1{16'h0101}}),
.cfg_mcf_rx_check_opcode_pfc('1),
.cfg_mcf_rx_forward('0),
.cfg_mcf_rx_enable('0),
.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('0),
.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('0),
.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('0),
.cfg_rx_pfc_opcode('{1{16'h0101}}),
.cfg_rx_pfc_en('0)
);
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)
)
sfp_mac_fifo (
/*
* AXI4-Stream input (sink)
*/
.s_clk(sfp_rx_clk),
.s_rst(sfp_rx_rst),
.s_axis(axis_sfp_rx[0]),
/*
* AXI4-Stream output (source)
*/
.m_clk(sfp_tx_clk),
.m_rst(sfp_tx_rst),
.m_axis(axis_sfp_tx[0]),
/*
* Pause
*/
.s_pause_req(1'b0),
.s_pause_ack(),
.m_pause_req(1'b0),
.m_pause_ack(),
/*
* Status
*/
.s_status_depth(),
.s_status_depth_commit(),
.s_status_overflow(),
.s_status_bad_frame(),
.s_status_good_frame(),
.m_status_depth(),
.m_status_depth_commit(),
.m_status_overflow(),
.m_status_bad_frame(),
.m_status_good_frame()
);
end
endmodule endmodule

View File

@@ -20,6 +20,7 @@ MODULE = $(COCOTB_TEST_MODULES)
TOPLEVEL = $(COCOTB_TOPLEVEL) TOPLEVEL = $(COCOTB_TOPLEVEL)
VERILOG_SOURCES += ../../rtl/$(DUT).sv VERILOG_SOURCES += ../../rtl/$(DUT).sv
VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f
VERILOG_SOURCES += ../../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us.f
VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_rgmii_fifo.f VERILOG_SOURCES += ../../lib/taxi/rtl/eth/taxi_eth_mac_1g_rgmii_fifo.f
VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_reset.sv VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_reset.sv
VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_signal.sv VERILOG_SOURCES += ../../lib/taxi/rtl/sync/taxi_sync_signal.sv
@@ -35,6 +36,7 @@ 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"
ifeq ($(SIM), icarus) ifeq ($(SIM), icarus)
PLUSARGS += -fst PLUSARGS += -fst

View File

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

View File

@@ -11,7 +11,9 @@ Authors:
import logging import logging
import os import os
import sys
import pytest
import cocotb_test.simulator import cocotb_test.simulator
import cocotb import cocotb
@@ -20,6 +22,17 @@ 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, GmiiSource, GmiiSink, RgmiiPhy
from cocotbext.eth import XgmiiFrame
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
except ImportError:
# attempt import from current directory
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
try:
from baser import BaseRSerdesSource, BaseRSerdesSink
finally:
del sys.path[0]
class TB: class TB:
@@ -29,18 +42,29 @@ class TB:
self.log = SimLog("cocotb.tb") self.log = SimLog("cocotb.tb")
self.log.setLevel(logging.DEBUG) self.log.setLevel(logging.DEBUG)
cocotb.start_soon(Clock(dut.sfp_gmii_clk, 8, units="ns").start())
self.baset_phy2 = RgmiiPhy(dut.phy2_rgmii_txd, dut.phy2_rgmii_tx_ctl, dut.phy2_rgmii_tx_clk, self.baset_phy2 = RgmiiPhy(dut.phy2_rgmii_txd, dut.phy2_rgmii_tx_ctl, dut.phy2_rgmii_tx_clk,
dut.phy2_rgmii_rxd, dut.phy2_rgmii_rx_ctl, dut.phy2_rgmii_rx_clk, speed=speed) dut.phy2_rgmii_rxd, dut.phy2_rgmii_rx_ctl, dut.phy2_rgmii_rx_clk, speed=speed)
self.baset_phy3 = RgmiiPhy(dut.phy3_rgmii_txd, dut.phy3_rgmii_tx_ctl, dut.phy3_rgmii_tx_clk, self.baset_phy3 = RgmiiPhy(dut.phy3_rgmii_txd, dut.phy3_rgmii_tx_ctl, dut.phy3_rgmii_tx_clk,
dut.phy3_rgmii_rxd, dut.phy3_rgmii_rx_ctl, dut.phy3_rgmii_rx_clk, speed=speed) dut.phy3_rgmii_rxd, dut.phy3_rgmii_rx_ctl, dut.phy3_rgmii_rx_clk, speed=speed)
if dut.SFP_RATE.value == 0:
cocotb.start_soon(Clock(dut.sfp_gmii_clk, 8, units="ns").start())
self.sfp_source = GmiiSource(dut.sfp_gmii_rxd, dut.sfp_gmii_rx_er, dut.sfp_gmii_rx_dv, self.sfp_source = 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) dut.sfp_gmii_clk, dut.sfp_gmii_rst, dut.sfp_gmii_clk_en)
self.sfp_sink = GmiiSink(dut.sfp_gmii_txd, dut.sfp_gmii_tx_er, dut.sfp_gmii_tx_en, self.sfp_sink = 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) 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]
cocotb.start_soon(Clock(ch.ch_inst.tx_clk, 6.4, units="ns").start())
cocotb.start_soon(Clock(ch.ch_inst.rx_clk, 6.4, units="ns").start())
self.sfp_source = BaseRSerdesSource(ch.ch_inst.serdes_rx_data, ch.ch_inst.serdes_rx_hdr, ch.ch_inst.rx_clk, slip=ch.ch_inst.serdes_rx_bitslip, reverse=True)
self.sfp_sink = BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.tx_clk, reverse=True)
cocotb.start_soon(self._run_clk()) cocotb.start_soon(self._run_clk())
@@ -61,6 +85,9 @@ class TB:
self.dut.rst.value = 0 self.dut.rst.value = 0
self.dut.sfp_gmii_rst.value = 0 self.dut.sfp_gmii_rst.value = 0
for k in range(10):
await RisingEdge(self.dut.clk)
async def _run_clk(self): async def _run_clk(self):
t = Timer(2, 'ns') t = Timer(2, 'ns')
while True: while True:
@@ -116,6 +143,46 @@ async def mac_test(tb, source, sink):
tb.log.info("MAC test done") tb.log.info("MAC test done")
async def mac_test_25g(tb, source, sink):
tb.log.info("Test MAC")
tb.log.info("Multiple small packets")
count = 64
pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)]
for p in pkts:
await source.send(XgmiiFrame.from_payload(p))
for k in range(count):
rx_frame = await sink.recv()
tb.log.info("RX frame: %s", rx_frame)
assert rx_frame.get_payload() == pkts[k]
assert rx_frame.check_fcs()
tb.log.info("Multiple large packets")
count = 32
pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)]
for p in pkts:
await source.send(XgmiiFrame.from_payload(p))
for k in range(count):
rx_frame = await sink.recv()
tb.log.info("RX frame: %s", rx_frame)
assert rx_frame.get_payload() == pkts[k]
assert rx_frame.check_fcs()
tb.log.info("MAC test done")
@cocotb.test() @cocotb.test()
async def run_test(dut): async def run_test(dut):
@@ -123,19 +190,24 @@ async def run_test(dut):
await tb.init() await tb.init()
tests = []
tb.log.info("Start BASE-T MAC loopback test on PHY2") tb.log.info("Start BASE-T MAC loopback test on PHY2")
phy2_test_cr = 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)))
tb.log.info("Start BASE-T MAC loopback test on PHY3") tb.log.info("Start BASE-T MAC loopback test on PHY3")
phy3_test_cr = 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)))
tb.log.info("Start SFP MAC loopback test") 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_source, tb.sfp_sink)))
else:
tb.log.info("Start 10G SFP MAC loopback test")
tests.append(cocotb.start_soon(mac_test_25g(tb, tb.sfp_source, tb.sfp_sink)))
sfp_test_cr = cocotb.start_soon(mac_test(tb, tb.sfp_source, tb.sfp_sink)) await Combine(*tests)
await Combine(phy2_test_cr, phy3_test_cr, sfp_test_cr)
await RisingEdge(dut.clk) await RisingEdge(dut.clk)
await RisingEdge(dut.clk) await RisingEdge(dut.clk)
@@ -161,7 +233,8 @@ def process_f_files(files):
return list(lst.values()) return list(lst.values())
def test_fpga_core(request): @pytest.mark.parametrize("sfp_rate", [0, 1])
def test_fpga_core(request, sfp_rate):
dut = "fpga_core" 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
@@ -169,6 +242,7 @@ def test_fpga_core(request):
verilog_sources = [ verilog_sources = [
os.path.join(rtl_dir, f"{dut}.sv"), os.path.join(rtl_dir, f"{dut}.sv"),
os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_fifo.f"), os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_fifo.f"),
os.path.join(lib_dir, "taxi", "rtl", "eth", "us", "taxi_eth_mac_25g_us.f"),
os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_rgmii_fifo.f"), os.path.join(lib_dir, "taxi", "rtl", "eth", "taxi_eth_mac_1g_rgmii_fifo.f"),
os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_reset.sv"), os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_reset.sv"),
os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_signal.sv"), os.path.join(lib_dir, "taxi", "rtl", "sync", "taxi_sync_signal.sv"),
@@ -182,6 +256,7 @@ def test_fpga_core(request):
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}"
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()}