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

@@ -15,7 +15,17 @@ Authors:
/*
* 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
@@ -59,19 +69,14 @@ module fpga
/*
* Ethernet: SFP+
*/
input wire logic sfp0_rx_p,
input wire logic sfp0_rx_n,
output wire logic sfp0_tx_p,
output wire logic sfp0_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 [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,
output wire logic sfp0_tx_disable_b,
output wire logic sfp1_tx_disable_b
output wire logic [1:0] sfp_tx_disable_b
);
// Clock and reset
@@ -346,176 +351,186 @@ eth_pcspma (
.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_rst_int;
wire sfp0_gmii_clk_en_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 [7:0] sfp0_gmii_rxd_int;
wire sfp0_gmii_rx_dv_int;
wire sfp0_gmii_rx_er_int;
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)
)
sync_reset_sfp0_inst (
.clk(sfp0_gmii_clk_int),
.rst(rst_125mhz_int || !sfp0_gmii_resetdone),
.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 [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(sfp0_tx_n),
.txp(sfp0_tx_p),
.rxn(sfp0_rx_n),
.rxp(sfp0_rx_p),
.independent_clock_bufg(clk_62mhz_int),
.userclk_out(sfp0_gmii_txuserclk),
.userclk2_out(sfp0_gmii_txuserclk2),
.rxuserclk_out(sfp0_gmii_rxuserclk),
.rxuserclk2_out(sfp0_gmii_rxuserclk2),
.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)
);
assign sfp0_gmii_clk_en_int = 1'b1;
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;
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;
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 [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];
if (SFP_RATE == 0) begin : sfp_phy
// 1000BASE-X
wire [4:0] sfp1_config_vect;
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 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 sfp0_gmii_clk_int = sfp0_gmii_txuserclk2;
basex_pcs_pma_1
sfp1_pcspma (
.gtrefclk(sfp0_gmii_gtrefclk),
.txn(sfp1_tx_n),
.txp(sfp1_tx_p),
.rxn(sfp1_rx_n),
.rxp(sfp1_rx_p),
.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(sfp0_gmii_txuserclk),
.rxuserclk2(sfp0_gmii_txuserclk2),
.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)
);
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)
);
assign sfp1_gmii_clk_en_int = 1'b1;
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(sfp0_gmii_rxuserclk),
.rxuserclk2_out(sfp0_gmii_rxuserclk2),
.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(sfp0_gmii_txuserclk),
.rxuserclk2(sfp0_gmii_txuserclk2),
.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)
);
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
@@ -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;
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 (
/*
* Clock: 125MHz
@@ -569,8 +589,15 @@ core_inst (
.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_rst(sfp0_gmii_rst_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_tx_en(sfp0_gmii_tx_en_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_rst(sfp1_gmii_rst_int),
@@ -591,7 +617,8 @@ core_inst (
.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),
.sfp1_tx_disable_b(sfp1_tx_disable_b)
.sfp_tx_disable_b(sfp_tx_disable_b)
);
endmodule