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

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2025-02-22 23:15:24 -08:00
parent 4a439783f1
commit b6be624bdb
9 changed files with 786 additions and 321 deletions

View File

@@ -12,12 +12,14 @@ The design places looped-back MACs on the BASE-T port and SFP+ cages, as well as
* Looped-back MAC via SGMII via Xilinx PCS/PMA core and LVDS IOSERDES * Looped-back MAC via SGMII via Xilinx PCS/PMA core and LVDS IOSERDES
* SFP+ cages * SFP+ cages
* 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: xcku040-ffva1156-2-e * FPGA: xcku040-ffva1156-2-e
* 1000BASE-T PHY: Marvell 88E1111 via SGMII * 1000BASE-T PHY: Marvell 88E1111 via SGMII
* 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

@@ -155,14 +155,14 @@ set_input_delay 0 [get_ports {phy_int_n}]
#set_input_delay 0 [get_ports {phy_mdio}] #set_input_delay 0 [get_ports {phy_mdio}]
# SFP+ interface # SFP+ interface
set_property -dict {LOC T2 } [get_ports {sfp0_rx_p}] ;# MGTYRXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 set_property -dict {LOC T2 } [get_ports {sfp_rx_p[0]}] ;# MGTYRXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC T1 } [get_ports {sfp0_rx_n}] ;# MGTYRXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 set_property -dict {LOC T1 } [get_ports {sfp_rx_n[0]}] ;# MGTYRXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC U4 } [get_ports {sfp0_tx_p}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 set_property -dict {LOC U4 } [get_ports {sfp_tx_p[0]}] ;# MGTYTXP2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC U3 } [get_ports {sfp0_tx_n}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2 set_property -dict {LOC U3 } [get_ports {sfp_tx_n[0]}] ;# MGTYTXN2_226 GTYE3_CHANNEL_X0Y10 / GTYE3_COMMON_X0Y2
set_property -dict {LOC V2 } [get_ports {sfp1_rx_p}] ;# MGTYRXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 set_property -dict {LOC V2 } [get_ports {sfp_rx_p[1]}] ;# MGTYRXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC V1 } [get_ports {sfp1_rx_n}] ;# MGTYRXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 set_property -dict {LOC V1 } [get_ports {sfp_rx_n[1]}] ;# MGTYRXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC W4 } [get_ports {sfp1_tx_p}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 set_property -dict {LOC W4 } [get_ports {sfp_tx_p[1]}] ;# MGTYTXP1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC W3 } [get_ports {sfp1_tx_n}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2 set_property -dict {LOC W3 } [get_ports {sfp_tx_n[1]}] ;# MGTYTXN1_226 GTYE3_CHANNEL_X0Y9 / GTYE3_COMMON_X0Y2
set_property -dict {LOC P6 } [get_ports sfp_mgt_refclk_0_p] ;# MGTREFCLK0P_227 from U32 Si570 via U104 Si53340 set_property -dict {LOC P6 } [get_ports sfp_mgt_refclk_0_p] ;# MGTREFCLK0P_227 from U32 Si570 via U104 Si53340
set_property -dict {LOC P5 } [get_ports sfp_mgt_refclk_0_n] ;# MGTREFCLK0N_227 from U32 Si570 via U104 Si53340 set_property -dict {LOC P5 } [get_ports sfp_mgt_refclk_0_n] ;# MGTREFCLK0N_227 from U32 Si570 via U104 Si53340
#set_property -dict {LOC M6 } [get_ports sfp_mgt_refclk_1_p] ;# MGTREFCLK1P_227 from U57 Si5328B #set_property -dict {LOC M6 } [get_ports sfp_mgt_refclk_1_p] ;# MGTREFCLK1P_227 from U57 Si5328B
@@ -170,8 +170,8 @@ set_property -dict {LOC P5 } [get_ports sfp_mgt_refclk_0_n] ;# MGTREFCLK0N_227
#set_property -dict {LOC AG11 IOSTANDARD LVDS} [get_ports sfp_recclk_p] ;# to U57 CKIN1 SI5328 #set_property -dict {LOC AG11 IOSTANDARD LVDS} [get_ports sfp_recclk_p] ;# to U57 CKIN1 SI5328
#set_property -dict {LOC AH11 IOSTANDARD LVDS} [get_ports sfp_recclk_n] ;# to U57 CKIN1 SI5328 #set_property -dict {LOC AH11 IOSTANDARD LVDS} [get_ports sfp_recclk_n] ;# to U57 CKIN1 SI5328
set_property -dict {LOC AL8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp0_tx_disable_b}] set_property -dict {LOC AL8 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_tx_disable_b[0]}]
set_property -dict {LOC D28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp1_tx_disable_b}] set_property -dict {LOC D28 IOSTANDARD LVCMOS18 SLEW SLOW DRIVE 8} [get_ports {sfp_tx_disable_b[1]}]
# 156.25 MHz MGT reference clock # 156.25 MHz MGT reference clock
create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports sfp_mgt_refclk_0_p] create_clock -period 6.400 -name sfp_mgt_refclk_0 [get_ports sfp_mgt_refclk_0_p]

View File

@@ -0,0 +1,48 @@
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2025 FPGA Ninja, LLC
#
# Authors:
# - Alex Forencich
#
# FPGA settings
FPGA_PART = xcku040-ffva1156-2-e
FPGA_TOP = fpga
FPGA_ARCH = kintexu
# Files for synthesis
SYN_FILES = ../rtl/fpga.sv
SYN_FILES += ../rtl/fpga_core.sv
SYN_FILES += ../lib/taxi/rtl/eth/taxi_eth_mac_1g_fifo.f
SYN_FILES += ../lib/taxi/rtl/eth/us/taxi_eth_mac_25g_us.f
SYN_FILES += ../lib/taxi/rtl/lss/taxi_uart.f
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_reset.sv
SYN_FILES += ../lib/taxi/rtl/sync/taxi_sync_signal.sv
SYN_FILES += ../lib/taxi/rtl/io/taxi_debounce_switch.sv
# XDC files
XDC_FILES = ../fpga.xdc
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 = ../ip/sgmii_pcs_pma_0.tcl
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

@@ -32,7 +32,7 @@ IP_TCL_FILES += ../ip/basex_pcs_pma_0.tcl
IP_TCL_FILES += ../ip/basex_pcs_pma_1.tcl IP_TCL_FILES += ../ip/basex_pcs_pma_1.tcl
# Configuration # Configuration
# CONFIG_TCL_FILES = ./config.tcl CONFIG_TCL_FILES = ./config.tcl
include ../common/vivado.mk include ../common/vivado.mk

View File

@@ -15,7 +15,17 @@ Authors:
/* /*
* FPGA top-level module * FPGA top-level module
*/ */
module fpga module fpga #
(
// simulation (set to avoid vendor primitives)
parameter logic SIM = 1'b0,
// vendor ("GENERIC", "XILINX", "ALTERA")
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "kintexu",
// SFP rate selection (0 for 1G, 1 for 10G)
parameter logic SFP_RATE = 1'b1
)
( (
/* /*
* Clock: 125MHz LVDS * Clock: 125MHz LVDS
@@ -59,19 +69,14 @@ module fpga
/* /*
* Ethernet: SFP+ * Ethernet: SFP+
*/ */
input wire logic sfp0_rx_p, input wire logic [1:0] sfp_rx_p,
input wire logic sfp0_rx_n, input wire logic [1:0] sfp_rx_n,
output wire logic sfp0_tx_p, output wire logic [1:0] sfp_tx_p,
output wire logic sfp0_tx_n, output wire logic [1:0] sfp_tx_n,
input wire logic sfp1_rx_p,
input wire logic sfp1_rx_n,
output wire logic sfp1_tx_p,
output wire logic sfp1_tx_n,
input wire logic sfp_mgt_refclk_0_p, input wire logic sfp_mgt_refclk_0_p,
input wire logic sfp_mgt_refclk_0_n, input wire logic sfp_mgt_refclk_0_n,
output wire logic sfp0_tx_disable_b, output wire logic [1:0] sfp_tx_disable_b
output wire logic sfp1_tx_disable_b
); );
// Clock and reset // Clock and reset
@@ -346,70 +351,88 @@ eth_pcspma (
.signal_detect (1'b1) .signal_detect (1'b1)
); );
// 1000BASE-X SFP // SFP+
wire [1:0] sfp_tx_p_int;
wire [1:0] sfp_tx_n_int;
wire sfp0_gmii_clk_int; wire sfp0_gmii_clk_int;
wire sfp0_gmii_rst_int; wire sfp0_gmii_rst_int;
wire sfp0_gmii_clk_en_int; wire sfp0_gmii_clk_en_int;
wire [7:0] sfp0_gmii_txd_int; wire [7:0] sfp0_gmii_txd_int;
wire sfp0_gmii_tx_en_int; wire sfp0_gmii_tx_en_int = 1'b1;
wire sfp0_gmii_tx_er_int; wire sfp0_gmii_tx_er_int;
wire [7:0] sfp0_gmii_rxd_int; wire [7:0] sfp0_gmii_rxd_int;
wire sfp0_gmii_rx_dv_int; wire sfp0_gmii_rx_dv_int;
wire sfp0_gmii_rx_er_int; wire sfp0_gmii_rx_er_int;
wire sfp0_gmii_gtrefclk; wire [15:0] sfp0_status_vect;
wire sfp0_gmii_txuserclk;
wire sfp0_gmii_txuserclk2;
wire sfp0_gmii_rxuserclk;
wire sfp0_gmii_rxuserclk2;
wire sfp0_gmii_resetdone;
wire sfp0_gmii_pmareset;
wire sfp0_gmii_mmcm_locked;
assign sfp0_gmii_clk_int = sfp0_gmii_txuserclk2; wire sfp1_gmii_clk_int;
wire sfp1_gmii_rst_int;
wire sfp1_gmii_clk_en_int;
wire [7:0] sfp1_gmii_txd_int;
wire sfp1_gmii_tx_en_int = 1'b1;
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;
taxi_sync_reset #( wire [15:0] sfp1_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_rxuserclk;
wire sfp0_gmii_rxuserclk2;
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) .N(4)
) )
sync_reset_sfp0_inst ( sync_reset_sfp0_inst (
.clk(sfp0_gmii_clk_int), .clk(sfp0_gmii_clk_int),
.rst(rst_125mhz_int || !sfp0_gmii_resetdone), .rst(rst_125mhz_int || !sfp0_gmii_resetdone),
.out(sfp0_gmii_rst_int) .out(sfp0_gmii_rst_int)
); );
wire [15:0] sfp0_status_vect; 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 sfp0_status_link_status = sfp0_status_vect[0]; wire [4:0] sfp0_config_vect;
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
assign sfp0_config_vect[4] = 1'b0; // autonegotiation enable basex_pcs_pma_0
assign sfp0_config_vect[3] = 1'b0; // isolate sfp0_pcspma (
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_p(sfp_mgt_refclk_0_p),
.gtrefclk_n(sfp_mgt_refclk_0_n), .gtrefclk_n(sfp_mgt_refclk_0_n),
.gtrefclk_out(sfp0_gmii_gtrefclk), .gtrefclk_out(sfp0_gmii_gtrefclk),
.txn(sfp0_tx_n), .txn(sfp_tx_n[0]),
.txp(sfp0_tx_p), .txp(sfp_tx_p[0]),
.rxn(sfp0_rx_n), .rxn(sfp_rx_n[0]),
.rxp(sfp0_rx_p), .rxp(sfp_rx_p[0]),
.independent_clock_bufg(clk_62mhz_int), .independent_clock_bufg(clk_62mhz_int),
.userclk_out(sfp0_gmii_txuserclk), .userclk_out(sfp0_gmii_txuserclk),
.userclk2_out(sfp0_gmii_txuserclk2), .userclk2_out(sfp0_gmii_txuserclk2),
@@ -430,65 +453,51 @@ sfp0_pcspma (
.status_vector(sfp0_status_vect), .status_vector(sfp0_status_vect),
.reset(rst_125mhz_int), .reset(rst_125mhz_int),
.signal_detect(1'b1) .signal_detect(1'b1)
); );
assign sfp0_gmii_clk_en_int = 1'b1; wire sfp1_gmii_txuserclk2 = sfp0_gmii_txuserclk2;
wire sfp1_gmii_resetdone;
wire sfp1_gmii_clk_int; assign sfp1_gmii_clk_int = sfp1_gmii_txuserclk2;
wire sfp1_gmii_rst_int;
wire sfp1_gmii_clk_en_int;
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 sfp1_gmii_txuserclk2 = sfp0_gmii_txuserclk2; taxi_sync_reset #(
wire sfp1_gmii_resetdone;
assign sfp1_gmii_clk_int = sfp1_gmii_txuserclk2;
taxi_sync_reset #(
.N(4) .N(4)
) )
sync_reset_sfp1_inst ( sync_reset_sfp1_inst (
.clk(sfp1_gmii_clk_int), .clk(sfp1_gmii_clk_int),
.rst(rst_125mhz_int || !sfp1_gmii_resetdone), .rst(rst_125mhz_int || !sfp1_gmii_resetdone),
.out(sfp1_gmii_rst_int) .out(sfp1_gmii_rst_int)
); );
wire [15:0] sfp1_status_vect; 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 sfp1_status_link_status = sfp1_status_vect[0]; wire [4:0] sfp1_config_vect;
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
assign sfp1_config_vect[4] = 1'b0; // autonegotiation enable basex_pcs_pma_1
assign sfp1_config_vect[3] = 1'b0; // isolate sfp1_pcspma (
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), .gtrefclk(sfp0_gmii_gtrefclk),
.txn(sfp1_tx_n), .txn(sfp_tx_n[1]),
.txp(sfp1_tx_p), .txp(sfp_tx_p[1]),
.rxn(sfp1_rx_n), .rxn(sfp_rx_n[1]),
.rxp(sfp1_rx_p), .rxp(sfp_rx_p[1]),
.independent_clock_bufg(clk_62mhz_int), .independent_clock_bufg(clk_62mhz_int),
.txoutclk(), .txoutclk(),
.gtpowergood(), .gtpowergood(),
@@ -513,9 +522,15 @@ sfp1_pcspma (
.status_vector(sfp1_status_vect), .status_vector(sfp1_status_vect),
.reset(rst_125mhz_int), .reset(rst_125mhz_int),
.signal_detect(1'b1) .signal_detect(1'b1)
); );
assign sfp1_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
// SGMII interface debug: // SGMII interface debug:
// SW12:1 (sw[3]) off for payload byte, on for status vector // SW12:1 (sw[3]) off for payload byte, on for status vector
@@ -525,7 +540,12 @@ assign sfp1_gmii_clk_en_int = 1'b1;
wire [15:0] sel_sv = sw[2] ? (sw[1] ? sfp1_status_vect : sfp0_status_vect) : sgmii_status_vect; wire [15:0] sel_sv = sw[2] ? (sw[1] ? sfp1_status_vect : sfp0_status_vect) : sgmii_status_vect;
assign led = sw[3] ? (sw[0] ? sel_sv[15:8] : sel_sv[7:0]) : led_int; assign led = sw[3] ? (sw[0] ? sel_sv[15:8] : sel_sv[7:0]) : led_int;
fpga_core fpga_core #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.SFP_RATE(SFP_RATE)
)
core_inst ( core_inst (
/* /*
* Clock: 125MHz * Clock: 125MHz
@@ -569,8 +589,15 @@ core_inst (
.phy_int_n(phy_int_n), .phy_int_n(phy_int_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_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_clk(sfp0_gmii_clk_int),
.sfp0_gmii_rst(sfp0_gmii_rst_int), .sfp0_gmii_rst(sfp0_gmii_rst_int),
.sfp0_gmii_clk_en(sfp0_gmii_clk_en_int), .sfp0_gmii_clk_en(sfp0_gmii_clk_en_int),
@@ -580,7 +607,6 @@ core_inst (
.sfp0_gmii_txd(sfp0_gmii_txd_int), .sfp0_gmii_txd(sfp0_gmii_txd_int),
.sfp0_gmii_tx_en(sfp0_gmii_tx_en_int), .sfp0_gmii_tx_en(sfp0_gmii_tx_en_int),
.sfp0_gmii_tx_er(sfp0_gmii_tx_er_int), .sfp0_gmii_tx_er(sfp0_gmii_tx_er_int),
.sfp0_tx_disable_b(sfp0_tx_disable_b),
.sfp1_gmii_clk(sfp1_gmii_clk_int), .sfp1_gmii_clk(sfp1_gmii_clk_int),
.sfp1_gmii_rst(sfp1_gmii_rst_int), .sfp1_gmii_rst(sfp1_gmii_rst_int),
@@ -591,7 +617,8 @@ core_inst (
.sfp1_gmii_txd(sfp1_gmii_txd_int), .sfp1_gmii_txd(sfp1_gmii_txd_int),
.sfp1_gmii_tx_en(sfp1_gmii_tx_en_int), .sfp1_gmii_tx_en(sfp1_gmii_tx_en_int),
.sfp1_gmii_tx_er(sfp1_gmii_tx_er_int), .sfp1_gmii_tx_er(sfp1_gmii_tx_er_int),
.sfp1_tx_disable_b(sfp1_tx_disable_b)
.sfp_tx_disable_b(sfp_tx_disable_b)
); );
endmodule endmodule

View File

@@ -15,7 +15,17 @@ Authors:
/* /*
* FPGA core logic * FPGA core logic
*/ */
module fpga_core module fpga_core #
(
// simulation (set to avoid vendor primitives)
parameter logic SIM = 1'b0,
// vendor ("GENERIC", "XILINX", "ALTERA")
parameter string VENDOR = "XILINX",
// device family
parameter string FAMILY = "kintexu",
// SFP rate selection (0 for 1G, 1 for 10G)
parameter logic SFP_RATE = 1'b1
)
( (
/* /*
* Clock: 125MHz * Clock: 125MHz
@@ -59,8 +69,16 @@ module fpga_core
input wire logic phy_int_n, input wire logic phy_int_n,
/* /*
* Ethernet: 1000BASE-X SFP * Ethernet: SFP+
*/ */
input wire logic [1:0] sfp_rx_p,
input wire logic [1:0] sfp_rx_n,
output wire logic [1:0] sfp_tx_p,
output wire logic [1:0] sfp_tx_n,
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_clk,
input wire logic sfp0_gmii_rst, input wire logic sfp0_gmii_rst,
input wire logic sfp0_gmii_clk_en, input wire logic sfp0_gmii_clk_en,
@@ -70,7 +88,6 @@ module fpga_core
output wire logic [7:0] sfp0_gmii_txd, output wire logic [7:0] sfp0_gmii_txd,
output wire logic sfp0_gmii_tx_en, output wire logic sfp0_gmii_tx_en,
output wire logic sfp0_gmii_tx_er, output wire logic sfp0_gmii_tx_er,
output wire logic sfp0_tx_disable_b,
input wire logic sfp1_gmii_clk, input wire logic sfp1_gmii_clk,
input wire logic sfp1_gmii_rst, input wire logic sfp1_gmii_rst,
@@ -81,7 +98,8 @@ module fpga_core
output wire logic [7:0] sfp1_gmii_txd, output wire logic [7:0] sfp1_gmii_txd,
output wire logic sfp1_gmii_tx_en, output wire logic sfp1_gmii_tx_en,
output wire logic sfp1_gmii_tx_er, output wire logic sfp1_gmii_tx_er,
output wire logic sfp1_tx_disable_b
output wire logic [1:0] sfp_tx_disable_b
); );
assign led = sw; assign led = sw;
@@ -199,24 +217,25 @@ eth_mac_inst (
); );
// SFP+ // SFP+
assign sfp0_tx_disable_b = 1'b1; assign sfp_tx_disable_b = '1;
assign sfp1_tx_disable_b = 1'b1;
taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp0_eth(); if (SFP_RATE == 0) begin : sfp_mac
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp0_tx_cpl();
taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp1_eth(); taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp0_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp1_tx_cpl(); taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp0_tx_cpl();
taxi_eth_mac_1g_fifo #( taxi_axis_if #(.DATA_W(8), .ID_W(8)) axis_sfp1_eth();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp1_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)
) )
sfp0_eth_mac_inst ( sfp0_eth_mac_inst (
.rx_clk(sfp0_gmii_clk), .rx_clk(sfp0_gmii_clk),
.rx_rst(sfp0_gmii_rst), .rx_rst(sfp0_gmii_rst),
.tx_clk(sfp0_gmii_clk), .tx_clk(sfp0_gmii_clk),
@@ -272,17 +291,17 @@ sfp0_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)
); );
taxi_eth_mac_1g_fifo #( 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)
) )
sfp1_eth_mac_inst ( sfp1_eth_mac_inst (
.rx_clk(sfp1_gmii_clk), .rx_clk(sfp1_gmii_clk),
.rx_rst(sfp1_gmii_rst), .rx_rst(sfp1_gmii_rst),
.tx_clk(sfp1_gmii_clk), .tx_clk(sfp1_gmii_clk),
@@ -338,7 +357,294 @@ sfp1_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 [1:0] sfp_tx_clk;
wire [1:0] sfp_tx_rst;
wire [1:0] sfp_rx_clk;
wire [1:0] sfp_rx_rst;
wire [1:0] sfp_rx_status;
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(64), .ID_W(8)) axis_sfp_tx[1:0]();
taxi_axis_if #(.DATA_W(96), .KEEP_W(1), .ID_W(8)) axis_sfp_tx_cpl[1:0]();
taxi_axis_if #(.DATA_W(64), .ID_W(8)) axis_sfp_rx[1:0]();
if (SIM) begin
assign sfp_gtpowergood = 1'b1;
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_GTE3 ibufds_gte3_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),
.out(sfp_rst)
);
taxi_eth_mac_25g_us #(
.SIM(SIM),
.VENDOR(VENDOR),
.FAMILY(FAMILY),
.CNT(2),
// 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_0),
.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('{2{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('{2{48'h01_80_C2_00_00_01}}),
.cfg_mcf_rx_check_eth_dst_mcast('1),
.cfg_mcf_rx_eth_dst_ucast('{2{48'd0}}),
.cfg_mcf_rx_check_eth_dst_ucast('0),
.cfg_mcf_rx_eth_src('{2{48'd0}}),
.cfg_mcf_rx_check_eth_src('0),
.cfg_mcf_rx_eth_type('{2{16'h8808}}),
.cfg_mcf_rx_opcode_lfc('{2{16'h0001}}),
.cfg_mcf_rx_check_opcode_lfc('1),
.cfg_mcf_rx_opcode_pfc('{2{16'h0101}}),
.cfg_mcf_rx_check_opcode_pfc('1),
.cfg_mcf_rx_forward('0),
.cfg_mcf_rx_enable('0),
.cfg_tx_lfc_eth_dst('{2{48'h01_80_C2_00_00_01}}),
.cfg_tx_lfc_eth_src('{2{48'h80_23_31_43_54_4C}}),
.cfg_tx_lfc_eth_type('{2{16'h8808}}),
.cfg_tx_lfc_opcode('{2{16'h0001}}),
.cfg_tx_lfc_en('0),
.cfg_tx_lfc_quanta('{2{16'hffff}}),
.cfg_tx_lfc_refresh('{2{16'h7fff}}),
.cfg_tx_pfc_eth_dst('{2{48'h01_80_C2_00_00_01}}),
.cfg_tx_pfc_eth_src('{2{48'h80_23_31_43_54_4C}}),
.cfg_tx_pfc_eth_type('{2{16'h8808}}),
.cfg_tx_pfc_opcode('{2{16'h0101}}),
.cfg_tx_pfc_en('0),
.cfg_tx_pfc_quanta('{2{'{8{16'hffff}}}}),
.cfg_tx_pfc_refresh('{2{'{8{16'h7fff}}}}),
.cfg_rx_lfc_opcode('{2{16'h0001}}),
.cfg_rx_lfc_en('0),
.cfg_rx_pfc_opcode('{2{16'h0101}}),
.cfg_rx_pfc_en('0)
);
for (genvar n = 0; n < 2; n = n + 1) begin : sfp_ch
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]),
/*
* AXI4-Stream output (source)
*/
.m_clk(sfp_tx_clk[n]),
.m_rst(sfp_tx_rst[n]),
.m_axis(axis_sfp_tx[n]),
/*
* 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
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/lss/taxi_uart.f VERILOG_SOURCES += ../../lib/taxi/rtl/lss/taxi_uart.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
@@ -32,7 +33,10 @@ uniq_base = $(if $1,$(call uniq_base,$(foreach f,$1,$(if $(filter-out $(notdir $
VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES))) VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters # module parameters
#export PARAM_A := value export PARAM_SIM := "1'b1"
export PARAM_VENDOR := "\"XILINX\""
export PARAM_FAMILY := "\"kintexu\""
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,8 +22,19 @@ from cocotb.clock import Clock
from cocotb.triggers import RisingEdge, Combine from cocotb.triggers import RisingEdge, Combine
from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink from cocotbext.eth import GmiiFrame, GmiiSource, GmiiSink
from cocotbext.eth import XgmiiFrame
from cocotbext.uart import UartSource, UartSink from cocotbext.uart import UartSource, UartSink
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:
def __init__(self, dut, speed=1000e6): def __init__(self, dut, speed=1000e6):
@@ -32,23 +45,37 @@ class TB:
cocotb.start_soon(Clock(dut.clk, 8, units="ns").start()) cocotb.start_soon(Clock(dut.clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.phy_gmii_clk, 8, units="ns").start()) cocotb.start_soon(Clock(dut.phy_gmii_clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.sfp0_gmii_clk, 8, units="ns").start())
cocotb.start_soon(Clock(dut.sfp1_gmii_clk, 8, units="ns").start())
self.gmii_source = GmiiSource(dut.phy_gmii_rxd, dut.phy_gmii_rx_er, dut.phy_gmii_rx_dv, self.gmii_source = GmiiSource(dut.phy_gmii_rxd, dut.phy_gmii_rx_er, dut.phy_gmii_rx_dv,
dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en) dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en)
self.gmii_sink = GmiiSink(dut.phy_gmii_txd, dut.phy_gmii_tx_er, dut.phy_gmii_tx_en, self.gmii_sink = GmiiSink(dut.phy_gmii_txd, dut.phy_gmii_tx_er, dut.phy_gmii_tx_en,
dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en) dut.phy_gmii_clk, dut.phy_gmii_rst, dut.phy_gmii_clk_en)
self.sfp0_source = GmiiSource(dut.sfp0_gmii_rxd, dut.sfp0_gmii_rx_er, dut.sfp0_gmii_rx_dv, self.sfp_sources = []
dut.sfp0_gmii_clk, dut.sfp0_gmii_rst, dut.sfp0_gmii_clk_en) self.sfp_sinks = []
self.sfp0_sink = 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.sfp1_source = GmiiSource(dut.sfp1_gmii_rxd, dut.sfp1_gmii_rx_er, dut.sfp1_gmii_rx_dv, if dut.SFP_RATE.value == 0:
dut.sfp1_gmii_clk, dut.sfp1_gmii_rst, dut.sfp1_gmii_clk_en) cocotb.start_soon(Clock(dut.sfp0_gmii_clk, 8, units="ns").start())
self.sfp1_sink = GmiiSink(dut.sfp1_gmii_txd, dut.sfp1_gmii_tx_er, dut.sfp1_gmii_tx_en, cocotb.start_soon(Clock(dut.sfp1_gmii_clk, 8, units="ns").start())
dut.sfp1_gmii_clk, dut.sfp1_gmii_rst, dut.sfp1_gmii_clk_en)
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))
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:
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_sources.append(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_sinks.append(BaseRSerdesSink(ch.ch_inst.serdes_tx_data, ch.ch_inst.serdes_tx_hdr, ch.ch_inst.tx_clk, reverse=True))
self.uart_source = UartSource(dut.uart_rxd, baud=115200, bits=8, stop_bits=1) self.uart_source = UartSource(dut.uart_rxd, baud=115200, bits=8, stop_bits=1)
self.uart_sink = UartSink(dut.uart_txd, baud=115200, bits=8, stop_bits=1) self.uart_sink = UartSink(dut.uart_txd, baud=115200, bits=8, stop_bits=1)
@@ -86,6 +113,9 @@ class TB:
self.dut.sfp0_gmii_rst.value = 0 self.dut.sfp0_gmii_rst.value = 0
self.dut.sfp1_gmii_rst.value = 0 self.dut.sfp1_gmii_rst.value = 0
for k in range(10):
await RisingEdge(self.dut.clk)
async def uart_test(tb, source, sink): async def uart_test(tb, source, sink):
tb.log.info("Test UART") tb.log.info("Test UART")
@@ -148,6 +178,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):
@@ -155,23 +225,25 @@ async def run_test(dut):
await tb.init() await tb.init()
tests = []
tb.log.info("Start UART test") tb.log.info("Start UART test")
uart_test_cr = cocotb.start_soon(uart_test(tb, tb.uart_source, tb.uart_sink)) tests.append(cocotb.start_soon(uart_test(tb, tb.uart_source, tb.uart_sink)))
tb.log.info("Start BASE-T MAC loopback test") tb.log.info("Start BASE-T MAC loopback test")
baset_test_cr = cocotb.start_soon(mac_test(tb, tb.gmii_source, tb.gmii_sink)) tests.append(cocotb.start_soon(mac_test(tb, tb.gmii_source, tb.gmii_sink)))
tb.log.info("Start SFP0 MAC loopback test") 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_25g(tb, tb.sfp_sources[k], tb.sfp_sinks[k])))
sfp0_test_cr = cocotb.start_soon(mac_test(tb, tb.sfp0_source, tb.sfp0_sink)) await Combine(*tests)
tb.log.info("Start SFP1 MAC loopback test")
sfp1_test_cr = cocotb.start_soon(mac_test(tb, tb.sfp1_source, tb.sfp1_sink))
await Combine(uart_test_cr, baset_test_cr, sfp0_test_cr, sfp1_test_cr)
await RisingEdge(dut.clk) await RisingEdge(dut.clk)
await RisingEdge(dut.clk) await RisingEdge(dut.clk)
@@ -197,7 +269,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
@@ -205,6 +278,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", "lss", "taxi_uart.f"), os.path.join(lib_dir, "taxi", "rtl", "lss", "taxi_uart.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"),
@@ -215,7 +289,10 @@ def test_fpga_core(request):
parameters = {} parameters = {}
# parameters['A'] = val parameters['SIM'] = "1'b1"
parameters['VENDOR'] = "\"XILINX\""
parameters['FAMILY'] = "\"kintexu\""
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()}