mirror of
https://github.com/fpganinja/taxi.git
synced 2026-08-28 07:35:01 -07:00
eth: Add support for USXGMII to 10GBASE-R MAC+PCS
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
taxi_eth_mac_phy_10g.sv
|
||||
taxi_eth_mac_phy_10g_rx.f
|
||||
taxi_eth_mac_phy_10g_tx.f
|
||||
taxi_eth_phy_10g_usxgmii_an.sv
|
||||
taxi_eth_mac_stats.f
|
||||
taxi_mac_ctrl_tx.sv
|
||||
taxi_mac_ctrl_rx.sv
|
||||
|
||||
@@ -21,6 +21,7 @@ module taxi_eth_mac_phy_10g #
|
||||
parameter HDR_W = (DATA_W/32),
|
||||
parameter logic TX_GBX_IF_EN = 1'b0,
|
||||
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
|
||||
parameter logic USXGMII_EN = 1'b0,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TD_EN = PTP_TS_EN,
|
||||
@@ -79,6 +80,27 @@ module taxi_eth_mac_phy_10g #
|
||||
output wire logic serdes_rx_bitslip,
|
||||
output wire logic serdes_rx_reset_req,
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
input wire logic an_en = 1'b1,
|
||||
input wire logic an_restart = 1'b0,
|
||||
input wire logic an_speedup = 1'b0,
|
||||
input wire logic an_timeout_en = 1'b1,
|
||||
input wire logic an_usxgmii_en = 1'b0,
|
||||
input wire logic an_usxgmii_auto = 1'b1,
|
||||
input wire logic an_usxgmii_5g = 1'b0,
|
||||
output wire logic an_intr,
|
||||
output wire logic an_running,
|
||||
output wire logic an_complete,
|
||||
output wire logic an_timeout,
|
||||
output wire logic an_usxgmii_mode,
|
||||
input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601,
|
||||
output wire logic [15:0] an_lp_adv_ability,
|
||||
output wire logic an_lp_usxgmii_link,
|
||||
output wire logic [2:0] an_lp_usxgmii_speed,
|
||||
output wire logic an_res_full_duplex,
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
@@ -356,10 +378,149 @@ end else begin
|
||||
|
||||
end
|
||||
|
||||
// USXGMII autonegotiation
|
||||
wire [23:0] rx_os;
|
||||
wire rx_os_sig;
|
||||
wire rx_os_valid;
|
||||
wire rx_os_match;
|
||||
wire rx_idle_match;
|
||||
|
||||
wire [23:0] tx_os;
|
||||
wire tx_os_sig;
|
||||
wire tx_os_valid;
|
||||
wire tx_os_ready;
|
||||
|
||||
wire cfg_rx_usxgmii_en;
|
||||
wire cfg_rx_usxgmii_5g;
|
||||
wire [2:0] cfg_rx_usxgmii_speed;
|
||||
|
||||
wire cfg_tx_usxgmii_en;
|
||||
wire cfg_tx_usxgmii_5g;
|
||||
wire [2:0] cfg_tx_usxgmii_speed;
|
||||
|
||||
if (USXGMII_EN) begin : an
|
||||
|
||||
// synchronize RX signals to TX
|
||||
wire [23:0] sync_rx_os;
|
||||
wire sync_rx_os_sig;
|
||||
wire sync_rx_os_valid;
|
||||
wire sync_rx_os_match;
|
||||
wire sync_rx_idle_match;
|
||||
wire sync_rx_block_lock;
|
||||
|
||||
taxi_sync_signal #(
|
||||
.WIDTH(24+5),
|
||||
.N(2)
|
||||
)
|
||||
rx_sync_inst (
|
||||
.clk(tx_clk),
|
||||
|
||||
.in({
|
||||
rx_os,
|
||||
rx_os_sig,
|
||||
rx_os_valid,
|
||||
rx_os_match,
|
||||
rx_idle_match,
|
||||
rx_block_lock
|
||||
}),
|
||||
.out({
|
||||
sync_rx_os,
|
||||
sync_rx_os_sig,
|
||||
sync_rx_os_valid,
|
||||
sync_rx_os_match,
|
||||
sync_rx_idle_match,
|
||||
sync_rx_block_lock
|
||||
})
|
||||
);
|
||||
|
||||
taxi_sync_signal #(
|
||||
.WIDTH(1+1+3),
|
||||
.N(2)
|
||||
)
|
||||
rx_sync_ctrl_inst (
|
||||
.clk(rx_clk),
|
||||
|
||||
.in({
|
||||
cfg_tx_usxgmii_en,
|
||||
cfg_tx_usxgmii_5g,
|
||||
cfg_tx_usxgmii_speed
|
||||
}),
|
||||
.out({
|
||||
cfg_rx_usxgmii_en,
|
||||
cfg_rx_usxgmii_5g,
|
||||
cfg_rx_usxgmii_speed
|
||||
})
|
||||
);
|
||||
|
||||
taxi_eth_phy_10g_usxgmii_an #(
|
||||
.DATA_W(DATA_W)
|
||||
)
|
||||
an_inst (
|
||||
.clk(tx_clk),
|
||||
.rst(tx_rst),
|
||||
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.rx_os(sync_rx_os),
|
||||
.rx_os_sig(sync_rx_os_sig),
|
||||
.rx_os_valid(sync_rx_os_valid),
|
||||
.rx_os_match(sync_rx_os_match),
|
||||
.rx_idle_match(sync_rx_idle_match),
|
||||
.rx_block_lock(sync_rx_block_lock),
|
||||
|
||||
.tx_os(tx_os),
|
||||
.tx_os_sig(tx_os_sig),
|
||||
.tx_os_valid(tx_os_valid),
|
||||
.tx_os_ready(tx_os_ready),
|
||||
|
||||
/*
|
||||
* USXGMII Autonegotiation
|
||||
*/
|
||||
.an_en(an_en),
|
||||
.an_restart(an_restart),
|
||||
.an_speedup(an_speedup),
|
||||
.an_timeout_en(an_timeout_en),
|
||||
.an_usxgmii_en(an_usxgmii_en),
|
||||
.an_usxgmii_auto(an_usxgmii_auto),
|
||||
.an_usxgmii_5g(an_usxgmii_5g),
|
||||
.an_intr(an_intr),
|
||||
.an_running(an_running),
|
||||
.an_complete(an_complete),
|
||||
.an_timeout(an_timeout),
|
||||
.an_usxgmii_mode(an_usxgmii_mode),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii),
|
||||
.an_lp_adv_ability(an_lp_adv_ability),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed),
|
||||
.an_res_full_duplex(an_res_full_duplex)
|
||||
);
|
||||
|
||||
assign cfg_tx_usxgmii_en = an_usxgmii_mode;
|
||||
assign cfg_tx_usxgmii_5g = an_usxgmii_5g;
|
||||
assign cfg_tx_usxgmii_speed = an_lp_usxgmii_speed;
|
||||
|
||||
end else begin : an
|
||||
|
||||
wire [23:0] tx_os = '0;
|
||||
wire tx_os_sig = 1'b0;
|
||||
wire tx_os_valid = 1'b0;
|
||||
|
||||
wire cfg_rx_usxgmii_en = 1'b0;
|
||||
wire cfg_rx_usxgmii_5g = 1'b0;
|
||||
wire [2:0] cfg_rx_usxgmii_speed = 3'b011;
|
||||
|
||||
wire cfg_tx_usxgmii_en = 1'b0;
|
||||
wire cfg_tx_usxgmii_5g = 1'b0;
|
||||
wire [2:0] cfg_tx_usxgmii_speed = 3'b011;
|
||||
|
||||
end
|
||||
|
||||
taxi_eth_mac_phy_10g_rx #(
|
||||
.DATA_W(DATA_W),
|
||||
.HDR_W(HDR_W),
|
||||
.GBX_IF_EN(RX_GBX_IF_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
|
||||
.PTP_TS_W(PTP_TS_W),
|
||||
@@ -390,6 +551,15 @@ eth_mac_phy_10g_rx_inst (
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.serdes_rx_reset_req(serdes_rx_reset_req),
|
||||
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.rx_os(rx_os),
|
||||
.rx_os_sig(rx_os_sig),
|
||||
.rx_os_valid(rx_os_valid),
|
||||
.rx_os_match(rx_os_match),
|
||||
.rx_idle_match(rx_idle_match),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
@@ -424,6 +594,9 @@ eth_mac_phy_10g_rx_inst (
|
||||
*/
|
||||
.cfg_rx_max_pkt_len(cfg_rx_max_pkt_len),
|
||||
.cfg_rx_enable(cfg_rx_enable),
|
||||
.cfg_rx_usxgmii_en(cfg_rx_usxgmii_en),
|
||||
.cfg_rx_usxgmii_5g(cfg_rx_usxgmii_5g),
|
||||
.cfg_rx_usxgmii_speed(cfg_rx_usxgmii_speed),
|
||||
.cfg_rx_prbs31_enable(cfg_rx_prbs31_enable)
|
||||
);
|
||||
|
||||
@@ -431,6 +604,7 @@ taxi_eth_mac_phy_10g_tx #(
|
||||
.DATA_W(DATA_W),
|
||||
.HDR_W(HDR_W),
|
||||
.GBX_IF_EN(TX_GBX_IF_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TS_FMT_TOD(PTP_TS_FMT_TOD),
|
||||
@@ -462,6 +636,14 @@ eth_mac_phy_10g_tx_inst (
|
||||
.serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall),
|
||||
.serdes_tx_gbx_sync(serdes_tx_gbx_sync),
|
||||
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.tx_os(tx_os),
|
||||
.tx_os_sig(tx_os_sig),
|
||||
.tx_os_valid(tx_os_valid),
|
||||
.tx_os_ready(tx_os_ready),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
@@ -492,6 +674,9 @@ eth_mac_phy_10g_tx_inst (
|
||||
.cfg_tx_max_pkt_len(cfg_tx_max_pkt_len),
|
||||
.cfg_tx_ifg(cfg_tx_ifg),
|
||||
.cfg_tx_enable(cfg_tx_enable),
|
||||
.cfg_tx_usxgmii_en(cfg_tx_usxgmii_en),
|
||||
.cfg_tx_usxgmii_5g(cfg_tx_usxgmii_5g),
|
||||
.cfg_tx_usxgmii_speed(cfg_tx_usxgmii_speed),
|
||||
.cfg_tx_prbs31_enable(cfg_tx_prbs31_enable)
|
||||
);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ module taxi_eth_mac_phy_10g_fifo #
|
||||
parameter HDR_W = (DATA_W/32),
|
||||
parameter logic TX_GBX_IF_EN = 1'b0,
|
||||
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
|
||||
parameter logic USXGMII_EN = 1'b0,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TD_EN = PTP_TS_EN,
|
||||
@@ -92,6 +93,27 @@ module taxi_eth_mac_phy_10g_fifo #
|
||||
output wire logic serdes_rx_bitslip,
|
||||
output wire logic serdes_rx_reset_req,
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
input wire logic an_en = 1'b1,
|
||||
input wire logic an_restart = 1'b0,
|
||||
input wire logic an_speedup = 1'b0,
|
||||
input wire logic an_timeout_en = 1'b1,
|
||||
input wire logic an_usxgmii_en = 1'b0,
|
||||
input wire logic an_usxgmii_auto = 1'b1,
|
||||
input wire logic an_usxgmii_5g = 1'b0,
|
||||
output wire logic an_intr,
|
||||
output wire logic an_running,
|
||||
output wire logic an_complete,
|
||||
output wire logic an_timeout,
|
||||
output wire logic an_usxgmii_mode,
|
||||
input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601,
|
||||
output wire logic [15:0] an_lp_adv_ability,
|
||||
output wire logic an_lp_usxgmii_link,
|
||||
output wire logic [2:0] an_lp_usxgmii_speed,
|
||||
output wire logic an_res_full_duplex,
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
@@ -300,6 +322,7 @@ taxi_eth_mac_phy_10g #(
|
||||
.HDR_W(HDR_W),
|
||||
.TX_GBX_IF_EN(TX_GBX_IF_EN),
|
||||
.RX_GBX_IF_EN(RX_GBX_IF_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TD_EN(PTP_TD_EN),
|
||||
@@ -356,6 +379,27 @@ eth_mac_phy_10g_inst (
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.serdes_rx_reset_req(serdes_rx_reset_req),
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
.an_en(an_en),
|
||||
.an_restart(an_restart),
|
||||
.an_speedup(an_speedup),
|
||||
.an_timeout_en(an_timeout_en),
|
||||
.an_usxgmii_en(an_usxgmii_en),
|
||||
.an_usxgmii_auto(an_usxgmii_auto),
|
||||
.an_usxgmii_5g(an_usxgmii_5g),
|
||||
.an_intr(an_intr),
|
||||
.an_running(an_running),
|
||||
.an_complete(an_complete),
|
||||
.an_timeout(an_timeout),
|
||||
.an_usxgmii_mode(an_usxgmii_mode),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii),
|
||||
.an_lp_adv_ability(an_lp_adv_ability),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed),
|
||||
.an_res_full_duplex(an_res_full_duplex),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,7 @@ module taxi_eth_mac_phy_10g_rx #
|
||||
parameter DATA_W = 64,
|
||||
parameter HDR_W = (DATA_W/32),
|
||||
parameter logic GBX_IF_EN = 1'b0,
|
||||
parameter logic USXGMII_EN = 1'b0,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TS_FMT_TOD = 1'b1,
|
||||
parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64,
|
||||
@@ -50,6 +51,15 @@ module taxi_eth_mac_phy_10g_rx #
|
||||
output wire logic serdes_rx_bitslip,
|
||||
output wire logic serdes_rx_reset_req,
|
||||
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
output wire logic [23:0] rx_os,
|
||||
output wire logic rx_os_sig,
|
||||
output wire logic rx_os_valid,
|
||||
output wire logic rx_os_match,
|
||||
output wire logic rx_idle_match,
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
@@ -84,6 +94,9 @@ module taxi_eth_mac_phy_10g_rx #
|
||||
*/
|
||||
input wire logic [15:0] cfg_rx_max_pkt_len = 16'd1518-1,
|
||||
input wire logic cfg_rx_enable,
|
||||
input wire logic cfg_rx_usxgmii_en = 1'b1,
|
||||
input wire logic cfg_rx_usxgmii_5g = 1'b0,
|
||||
input wire logic [2:0] cfg_rx_usxgmii_speed = 3'b011,
|
||||
input wire logic cfg_rx_prbs31_enable
|
||||
);
|
||||
|
||||
@@ -144,6 +157,9 @@ eth_phy_10g_rx_if_inst (
|
||||
|
||||
if (DATA_W == 64) begin
|
||||
|
||||
if (USXGMII_EN)
|
||||
$fatal(0, "Error: USXGMII is not currently supported in 64-bit mode (instance %m)");
|
||||
|
||||
taxi_axis_baser_rx_64 #(
|
||||
.DATA_W(DATA_W),
|
||||
.HDR_W(HDR_W),
|
||||
@@ -172,11 +188,11 @@ if (DATA_W == 64) begin
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.rx_os(),
|
||||
.rx_os_sig(),
|
||||
.rx_os_valid(),
|
||||
.rx_os_match(),
|
||||
.rx_idle_match(),
|
||||
.rx_os(rx_os),
|
||||
.rx_os_sig(rx_os_sig),
|
||||
.rx_os_valid(rx_os_valid),
|
||||
.rx_os_match(rx_os_match),
|
||||
.rx_idle_match(rx_idle_match),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
@@ -216,6 +232,7 @@ end else begin
|
||||
.DATA_W(DATA_W),
|
||||
.HDR_W(HDR_W),
|
||||
.GBX_IF_EN(GBX_IF_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TS_W(PTP_TS_W)
|
||||
)
|
||||
@@ -239,11 +256,11 @@ end else begin
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.rx_os(),
|
||||
.rx_os_sig(),
|
||||
.rx_os_valid(),
|
||||
.rx_os_match(),
|
||||
.rx_idle_match(),
|
||||
.rx_os(rx_os),
|
||||
.rx_os_sig(rx_os_sig),
|
||||
.rx_os_valid(rx_os_valid),
|
||||
.rx_os_match(rx_os_match),
|
||||
.rx_idle_match(rx_idle_match),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
@@ -255,6 +272,9 @@ end else begin
|
||||
*/
|
||||
.cfg_rx_max_pkt_len(cfg_rx_max_pkt_len),
|
||||
.cfg_rx_enable(cfg_rx_enable),
|
||||
.cfg_rx_usxgmii_en(cfg_rx_usxgmii_en),
|
||||
.cfg_rx_usxgmii_5g(cfg_rx_usxgmii_5g),
|
||||
.cfg_rx_usxgmii_speed(cfg_rx_usxgmii_speed),
|
||||
|
||||
/*
|
||||
* Status
|
||||
|
||||
@@ -20,6 +20,7 @@ module taxi_eth_mac_phy_10g_tx #
|
||||
parameter DATA_W = 64,
|
||||
parameter HDR_W = (DATA_W/32),
|
||||
parameter logic GBX_IF_EN = 1'b0,
|
||||
parameter logic USXGMII_EN = 1'b0,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TS_FMT_TOD = 1'b1,
|
||||
@@ -51,6 +52,14 @@ module taxi_eth_mac_phy_10g_tx #
|
||||
input wire logic serdes_tx_gbx_req_stall = 1'b0,
|
||||
output wire logic serdes_tx_gbx_sync,
|
||||
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
input wire logic [23:0] tx_os = '0,
|
||||
input wire logic tx_os_sig = 1'b0,
|
||||
input wire logic tx_os_valid = 1'b0,
|
||||
output wire logic tx_os_ready,
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
@@ -81,6 +90,9 @@ module taxi_eth_mac_phy_10g_tx #
|
||||
input wire logic [15:0] cfg_tx_max_pkt_len = 16'd1518-1,
|
||||
input wire logic [7:0] cfg_tx_ifg = 8'd12,
|
||||
input wire logic cfg_tx_enable,
|
||||
input wire logic cfg_tx_usxgmii_en = 1'b1,
|
||||
input wire logic cfg_tx_usxgmii_5g = 1'b0,
|
||||
input wire logic [2:0] cfg_tx_usxgmii_speed = 3'b011,
|
||||
input wire logic cfg_tx_prbs31_enable
|
||||
);
|
||||
|
||||
@@ -135,6 +147,9 @@ tx_pad_inst (
|
||||
|
||||
if (DATA_W == 64) begin
|
||||
|
||||
if (USXGMII_EN)
|
||||
$fatal(0, "Error: USXGMII is not currently supported in 64-bit mode (instance %m)");
|
||||
|
||||
taxi_axis_baser_tx_64 #(
|
||||
.DATA_W(DATA_W),
|
||||
.HDR_W(HDR_W),
|
||||
@@ -170,10 +185,10 @@ if (DATA_W == 64) begin
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.tx_os('0),
|
||||
.tx_os_sig(1'b0),
|
||||
.tx_os_valid(1'b0),
|
||||
.tx_os_ready(),
|
||||
.tx_os(tx_os),
|
||||
.tx_os_sig(tx_os_sig),
|
||||
.tx_os_valid(tx_os_valid),
|
||||
.tx_os_ready(tx_os_ready),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
@@ -211,6 +226,7 @@ end else begin
|
||||
.HDR_W(HDR_W),
|
||||
.GBX_IF_EN(GBX_IF_EN),
|
||||
.GBX_CNT(1),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TS_W(PTP_TS_W),
|
||||
@@ -240,10 +256,10 @@ end else begin
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
.tx_os('0),
|
||||
.tx_os_sig(1'b0),
|
||||
.tx_os_valid(1'b0),
|
||||
.tx_os_ready(),
|
||||
.tx_os(tx_os),
|
||||
.tx_os_sig(tx_os_sig),
|
||||
.tx_os_valid(tx_os_valid),
|
||||
.tx_os_ready(tx_os_ready),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
@@ -256,6 +272,9 @@ end else begin
|
||||
.cfg_tx_max_pkt_len(cfg_tx_max_pkt_len),
|
||||
.cfg_tx_ifg(cfg_tx_ifg),
|
||||
.cfg_tx_enable(cfg_tx_enable),
|
||||
.cfg_tx_usxgmii_en(cfg_tx_usxgmii_en),
|
||||
.cfg_tx_usxgmii_5g(cfg_tx_usxgmii_5g),
|
||||
.cfg_tx_usxgmii_speed(cfg_tx_usxgmii_speed),
|
||||
|
||||
/*
|
||||
* Status
|
||||
|
||||
374
src/eth/rtl/taxi_eth_phy_10g_usxgmii_an.sv
Normal file
374
src/eth/rtl/taxi_eth_phy_10g_usxgmii_an.sv
Normal file
@@ -0,0 +1,374 @@
|
||||
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
module taxi_eth_phy_10g_usxgmii_an #
|
||||
(
|
||||
parameter DATA_W = 32
|
||||
)
|
||||
(
|
||||
input wire logic clk,
|
||||
input wire logic rst,
|
||||
|
||||
/*
|
||||
* Ordered sets
|
||||
*/
|
||||
input wire logic [23:0] rx_os,
|
||||
input wire logic rx_os_sig,
|
||||
input wire logic rx_os_valid,
|
||||
input wire logic rx_os_match,
|
||||
input wire logic rx_idle_match,
|
||||
input wire logic rx_block_lock,
|
||||
|
||||
output wire logic [23:0] tx_os,
|
||||
output wire logic tx_os_sig,
|
||||
output wire logic tx_os_valid,
|
||||
input wire logic tx_os_ready,
|
||||
|
||||
/*
|
||||
* USXGMII Autonegotiation
|
||||
*/
|
||||
input wire logic an_en = 1'b1,
|
||||
input wire logic an_restart = 1'b0,
|
||||
input wire logic an_speedup = 1'b0,
|
||||
input wire logic an_timeout_en = 1'b1,
|
||||
input wire logic an_usxgmii_en = 1'b0,
|
||||
input wire logic an_usxgmii_auto = 1'b1,
|
||||
input wire logic an_usxgmii_5g = 1'b0,
|
||||
output wire logic an_intr,
|
||||
output wire logic an_running,
|
||||
output wire logic an_complete,
|
||||
output wire logic an_timeout,
|
||||
output wire logic an_usxgmii_mode,
|
||||
input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601,
|
||||
output wire logic [15:0] an_lp_adv_ability,
|
||||
output wire logic an_lp_usxgmii_link,
|
||||
output wire logic [2:0] an_lp_usxgmii_speed,
|
||||
output wire logic an_res_full_duplex
|
||||
);
|
||||
|
||||
localparam logic [15:0] AN_ACK = 16'h4000;
|
||||
localparam logic [15:0] AN_NP = 16'h8000;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
STATE_START,
|
||||
STATE_AN_RESTART,
|
||||
STATE_ABILITY_DET,
|
||||
STATE_ACK_DET,
|
||||
STATE_ACK_CPL,
|
||||
STATE_IDLE_DET,
|
||||
STATE_DONE
|
||||
} state_t;
|
||||
|
||||
state_t state_reg = STATE_START, state_next;
|
||||
|
||||
// 1 pulse per 100 us for timers
|
||||
localparam CYC_PER_US = DATA_W == 64 ? 156 : 312;
|
||||
localparam PRESC_CYC = $rtoi(CYC_PER_US*100);
|
||||
|
||||
logic [16:0] presc_cnt_reg = '0;
|
||||
logic presc_pulse_reg = 1'b0;
|
||||
logic [4:0] delay_cnt_reg = '0, delay_cnt_next;
|
||||
logic delay_run_reg = 1'b0, delay_run_next;
|
||||
logic [9:0] timeout_cnt_reg = '0, timeout_cnt_next;
|
||||
logic timeout_run_reg = 1'b0, timeout_run_next;
|
||||
|
||||
logic [23:0] tx_os_reg = '0, tx_os_next;
|
||||
logic tx_os_valid_reg = 1'b0, tx_os_valid_next;
|
||||
|
||||
logic an_intr_reg = 1'b0, an_intr_next;
|
||||
logic an_running_reg = 1'b0, an_running_next;
|
||||
logic an_complete_reg = 1'b0, an_complete_next;
|
||||
logic an_timeout_reg = 1'b0, an_timeout_next;
|
||||
logic an_usxgmii_mode_reg = 1'b0, an_usxgmii_mode_next;
|
||||
logic [15:0] an_lp_adv_ability_reg = '0, an_lp_adv_ability_next;
|
||||
|
||||
assign tx_os = tx_os_reg;
|
||||
assign tx_os_sig = 1'b0;
|
||||
assign tx_os_valid = tx_os_valid_reg;
|
||||
|
||||
assign an_intr = an_intr_reg;
|
||||
assign an_running = an_running_reg;
|
||||
assign an_complete = an_complete_reg;
|
||||
assign an_timeout = an_timeout_reg;
|
||||
assign an_usxgmii_mode = an_usxgmii_mode_reg;
|
||||
assign an_lp_adv_ability = an_lp_adv_ability_reg;
|
||||
|
||||
// extract config information from link partner ability value
|
||||
assign an_lp_usxgmii_link = an_usxgmii_mode_reg ? an_lp_adv_ability_reg[15] : 1'b1;
|
||||
assign an_lp_usxgmii_speed = an_usxgmii_mode_reg ? an_lp_adv_ability_reg[11:9] : 3'b011;
|
||||
assign an_res_full_duplex = an_usxgmii_mode_reg ? an_lp_adv_ability_reg[12] : 1'b1;
|
||||
|
||||
// TODO: check for stabilized RX config reg values
|
||||
|
||||
always_comb begin
|
||||
state_next = STATE_START;
|
||||
|
||||
delay_cnt_next = delay_cnt_reg;
|
||||
delay_run_next = delay_run_reg;
|
||||
timeout_cnt_next = timeout_cnt_reg;
|
||||
timeout_run_next = timeout_run_reg;
|
||||
|
||||
tx_os_next = tx_os_reg;
|
||||
tx_os_valid_next = tx_os_valid_reg && !tx_os_ready;
|
||||
|
||||
an_intr_next = 1'b0;
|
||||
an_running_next = an_running_reg;
|
||||
an_complete_next = an_complete_reg;
|
||||
an_timeout_next = an_timeout_reg;
|
||||
an_usxgmii_mode_next = an_usxgmii_mode_reg;
|
||||
an_lp_adv_ability_next = an_lp_adv_ability_reg;
|
||||
|
||||
if (delay_run_reg) begin
|
||||
if (presc_pulse_reg) begin
|
||||
if (delay_cnt_reg != 0) begin
|
||||
delay_cnt_next = delay_cnt_reg - 1;
|
||||
end else begin
|
||||
delay_run_next = 1'b0;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// USXGMII: 1.6 ms timer
|
||||
delay_cnt_next = 16;
|
||||
end
|
||||
|
||||
if (timeout_run_reg) begin
|
||||
if (presc_pulse_reg) begin
|
||||
if (timeout_cnt_reg != 0) begin
|
||||
timeout_cnt_next = timeout_cnt_reg - 1;
|
||||
end else begin
|
||||
timeout_run_next = 1'b0;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// 100 ms timer
|
||||
timeout_cnt_next = 1000;
|
||||
end
|
||||
|
||||
case (state_reg)
|
||||
STATE_START: begin
|
||||
// start
|
||||
an_running_next = 1'b0;
|
||||
an_complete_next = 1'b0;
|
||||
an_timeout_next = 1'b0;
|
||||
timeout_run_next = 1'b0;
|
||||
|
||||
if (an_usxgmii_en) begin
|
||||
an_usxgmii_mode_next = 1'b1;
|
||||
end else if (!an_usxgmii_auto) begin
|
||||
an_usxgmii_mode_next = 1'b0;
|
||||
end
|
||||
|
||||
tx_os_next = {16'd0, 8'h03};
|
||||
|
||||
if (an_en) begin
|
||||
if (!an_usxgmii_mode_next) begin
|
||||
state_next = STATE_DONE;
|
||||
end else begin
|
||||
tx_os_valid_next = 1'b1;
|
||||
if (delay_run_reg) begin
|
||||
// restart link timer
|
||||
delay_run_next = 1'b0;
|
||||
state_next = STATE_START;
|
||||
end else begin
|
||||
// AN restart state
|
||||
delay_run_next = 1'b1;
|
||||
an_running_next = 1'b1;
|
||||
state_next = STATE_AN_RESTART;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// AN disabled
|
||||
an_usxgmii_mode_next = 1'b0;
|
||||
state_next = STATE_START;
|
||||
end
|
||||
end
|
||||
STATE_AN_RESTART: begin
|
||||
// AN restart - send zeroed config reg to trigger link partner to restart the AN process
|
||||
tx_os_next = {16'd0, 8'h03};
|
||||
tx_os_valid_next = 1'b1;
|
||||
|
||||
if (!delay_run_reg) begin
|
||||
// link timer expired
|
||||
timeout_run_next = 1'b1;
|
||||
state_next = STATE_ABILITY_DET;
|
||||
end else begin
|
||||
state_next = STATE_AN_RESTART;
|
||||
end
|
||||
end
|
||||
STATE_ABILITY_DET: begin
|
||||
// ability detect state - transfer AN ability value with ACK clear
|
||||
tx_os_next[23:8] = an_adv_ability_usxgmii & ~AN_ACK;
|
||||
tx_os_valid_next = 1'b1;
|
||||
|
||||
if (rx_os_match && rx_os[23:8] != 0 && rx_os[7:0] == 8'h03) begin
|
||||
// got USXGMII ability advertisement from link partner
|
||||
an_lp_adv_ability_next = rx_os[23:8];
|
||||
state_next = STATE_ACK_DET;
|
||||
end else if (!timeout_run_reg && an_timeout_en) begin
|
||||
// timed out, no AN response from link partner
|
||||
an_timeout_next = 1'b1;
|
||||
if (!an_usxgmii_en) begin
|
||||
an_usxgmii_mode_next = 1'b0;
|
||||
end
|
||||
state_next = STATE_DONE;
|
||||
end else begin
|
||||
state_next = STATE_ABILITY_DET;
|
||||
end
|
||||
end
|
||||
STATE_ACK_DET: begin
|
||||
// acknowledge detect - wait for ACK from link partner
|
||||
tx_os_next[23:8] = tx_os_reg[23:8] | AN_ACK;
|
||||
tx_os_valid_next = 1'b1;
|
||||
|
||||
if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else if (rx_os_match && rx_os[14+8] && rx_os[7:0] == 8'h03) begin
|
||||
// acknowledge match
|
||||
an_lp_adv_ability_next = rx_os[23:8];
|
||||
if (rx_os[23:8] == (an_lp_adv_ability_reg | AN_ACK)) begin
|
||||
// consistent with previously-seen value
|
||||
delay_run_next = 1'b1;
|
||||
state_next = STATE_ACK_CPL;
|
||||
end else begin
|
||||
// inconsistent, restart AN
|
||||
state_next = STATE_START;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_ACK_DET;
|
||||
end
|
||||
end
|
||||
STATE_ACK_CPL: begin
|
||||
// complete acknowledge - give link partner time to detect our ACK
|
||||
tx_os_next[23:8] = tx_os_reg[23:8] | AN_ACK;
|
||||
tx_os_valid_next = 1'b1;
|
||||
|
||||
if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else if (!delay_run_reg) begin
|
||||
// link timer expired
|
||||
if (an_lp_adv_ability_reg[0] == 1'b1 && rx_os[7:0] == 8'h03) begin
|
||||
// mode matches
|
||||
delay_run_next = 1'b1;
|
||||
state_next = STATE_IDLE_DET;
|
||||
end else begin
|
||||
// mode mismatch
|
||||
if (an_usxgmii_en) begin
|
||||
state_next = STATE_START;
|
||||
end else begin
|
||||
an_usxgmii_mode_next = 1'b0;
|
||||
state_next = STATE_DONE;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_ACK_CPL;
|
||||
end
|
||||
end
|
||||
STATE_IDLE_DET: begin
|
||||
// idle detect - wait for link to go idle
|
||||
if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else if (rx_idle_match && !delay_run_reg) begin
|
||||
// idle match and link timer expired
|
||||
an_complete_next = 1'b1;
|
||||
state_next = STATE_DONE;
|
||||
end else begin
|
||||
state_next = STATE_IDLE_DET;
|
||||
end
|
||||
end
|
||||
STATE_DONE: begin
|
||||
// AN operation complete
|
||||
an_running_next = 1'b0;
|
||||
timeout_run_next = 1'b0;
|
||||
|
||||
if (rx_os_match && rx_os[23:8] == 0 && rx_os[7:0] == 8'h03) begin
|
||||
// restart request from link partner
|
||||
an_usxgmii_mode_next = 1'b1;
|
||||
state_next = STATE_START;
|
||||
end else begin
|
||||
state_next = STATE_DONE;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
state_next = STATE_START;
|
||||
end
|
||||
endcase
|
||||
|
||||
if (!an_en || an_restart || !rx_block_lock) begin
|
||||
an_usxgmii_mode_next = an_en && an_usxgmii_en;
|
||||
if (an_usxgmii_en) begin
|
||||
an_usxgmii_mode_next = 1'b1;
|
||||
end else if (!an_usxgmii_auto) begin
|
||||
an_usxgmii_mode_next = 1'b0;
|
||||
end else if (an_usxgmii_auto && rx_os_match && rx_os[7:0] == 8'h03) begin
|
||||
an_usxgmii_mode_next = 1'b1;
|
||||
end
|
||||
state_next = STATE_START;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
delay_cnt_reg <= delay_cnt_next;
|
||||
delay_run_reg <= delay_run_next;
|
||||
timeout_cnt_reg <= timeout_cnt_next;
|
||||
timeout_run_reg <= timeout_run_next;
|
||||
|
||||
tx_os_reg <= tx_os_next;
|
||||
tx_os_valid_reg <= tx_os_valid_next;
|
||||
|
||||
an_intr_reg <= an_intr_next;
|
||||
an_running_reg <= an_running_next;
|
||||
an_complete_reg <= an_complete_next;
|
||||
an_timeout_reg <= an_timeout_next;
|
||||
an_usxgmii_mode_reg <= an_usxgmii_mode_next;
|
||||
an_lp_adv_ability_reg <= an_lp_adv_ability_next;
|
||||
|
||||
presc_pulse_reg <= 1'b0;
|
||||
if (presc_cnt_reg != 0) begin
|
||||
presc_cnt_reg <= presc_cnt_reg - 1;
|
||||
end else begin
|
||||
presc_pulse_reg <= 1'b1;
|
||||
presc_cnt_reg <= 17'(an_speedup ? PRESC_CYC / 1000 : PRESC_CYC);
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
state_reg <= STATE_START;
|
||||
|
||||
presc_cnt_reg <= '0;
|
||||
presc_pulse_reg <= 1'b0;
|
||||
delay_cnt_reg <= '0;
|
||||
delay_run_reg <= 1'b0;
|
||||
timeout_cnt_reg <= '0;
|
||||
timeout_run_reg <= 1'b0;
|
||||
|
||||
tx_os_valid_reg <= 1'b0;
|
||||
|
||||
an_intr_reg <= 1'b0;
|
||||
an_running_reg <= 1'b0;
|
||||
an_complete_reg <= 1'b0;
|
||||
an_timeout_reg <= 1'b0;
|
||||
an_usxgmii_mode_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
@@ -54,6 +54,7 @@ module taxi_eth_mac_25g_us #
|
||||
// MAC/PHY parameters
|
||||
parameter logic COMBINED_MAC_PCS = 1'b1,
|
||||
parameter DATA_W = 64,
|
||||
parameter logic USXGMII_EN = 1'b0,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TD_EN = PTP_TS_EN,
|
||||
@@ -133,6 +134,26 @@ module taxi_eth_mac_25g_us #
|
||||
*/
|
||||
taxi_axis_if.src m_axis_rx[CNT],
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
input wire logic an_en[CNT] = '{CNT{1'b1}},
|
||||
input wire logic an_restart[CNT] = '{CNT{1'b0}},
|
||||
input wire logic an_speedup[CNT] = '{CNT{1'b0}},
|
||||
input wire logic an_timeout_en[CNT] = '{CNT{1'b1}},
|
||||
input wire logic an_usxgmii_en[CNT] = '{CNT{1'b0}},
|
||||
input wire logic an_usxgmii_auto[CNT] = '{CNT{1'b1}},
|
||||
output wire logic an_intr[CNT],
|
||||
output wire logic an_running[CNT],
|
||||
output wire logic an_complete[CNT],
|
||||
output wire logic an_timeout[CNT],
|
||||
output wire logic an_usxgmii_mode[CNT],
|
||||
input wire logic [15:0] an_adv_ability_usxgmii[CNT] = '{CNT{16'h1601}},
|
||||
output wire logic [15:0] an_lp_adv_ability[CNT],
|
||||
output wire logic an_lp_usxgmii_link[CNT],
|
||||
output wire logic [2:0] an_lp_usxgmii_speed[CNT],
|
||||
output wire logic an_res_full_duplex[CNT],
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
@@ -426,6 +447,7 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch
|
||||
// MAC/PHY parameters
|
||||
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
|
||||
.DATA_W(DATA_W),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TD_EN(PTP_TD_EN),
|
||||
@@ -519,6 +541,26 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch
|
||||
*/
|
||||
.m_axis_rx(m_axis_rx[n]),
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
.an_en(an_en[n]),
|
||||
.an_restart(an_restart[n]),
|
||||
.an_speedup(an_speedup[n]),
|
||||
.an_timeout_en(an_timeout_en[n]),
|
||||
.an_usxgmii_en(an_usxgmii_en[n]),
|
||||
.an_usxgmii_auto(an_usxgmii_auto[n]),
|
||||
.an_intr(an_intr[n]),
|
||||
.an_running(an_running[n]),
|
||||
.an_complete(an_complete[n]),
|
||||
.an_timeout(an_timeout[n]),
|
||||
.an_usxgmii_mode(an_usxgmii_mode[n]),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii[n]),
|
||||
.an_lp_adv_ability(an_lp_adv_ability[n]),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link[n]),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed[n]),
|
||||
.an_res_full_duplex(an_res_full_duplex[n]),
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
|
||||
@@ -53,6 +53,7 @@ module taxi_eth_mac_25g_us_ch #
|
||||
// MAC/PHY parameters
|
||||
parameter logic COMBINED_MAC_PCS = 1'b1,
|
||||
parameter DATA_W = 64,
|
||||
parameter logic USXGMII_EN = 1'b0,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TD_EN = PTP_TS_EN,
|
||||
@@ -146,6 +147,26 @@ module taxi_eth_mac_25g_us_ch #
|
||||
*/
|
||||
taxi_axis_if.src m_axis_rx,
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
input wire logic an_en = 1'b1,
|
||||
input wire logic an_restart = 1'b0,
|
||||
input wire logic an_speedup = 1'b0,
|
||||
input wire logic an_timeout_en = 1'b1,
|
||||
input wire logic an_usxgmii_en = 1'b0,
|
||||
input wire logic an_usxgmii_auto = 1'b1,
|
||||
output wire logic an_intr,
|
||||
output wire logic an_running,
|
||||
output wire logic an_complete,
|
||||
output wire logic an_timeout,
|
||||
output wire logic an_usxgmii_mode,
|
||||
input wire logic [15:0] an_adv_ability_usxgmii = 16'h1601,
|
||||
output wire logic [15:0] an_lp_adv_ability,
|
||||
output wire logic an_lp_usxgmii_link,
|
||||
output wire logic [2:0] an_lp_usxgmii_speed,
|
||||
output wire logic an_res_full_duplex,
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
@@ -885,6 +906,7 @@ if (COMBINED_MAC_PCS) begin : mac
|
||||
.HDR_W(HDR_W),
|
||||
.TX_GBX_IF_EN(GBX_EN),
|
||||
.RX_GBX_IF_EN(GBX_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TD_EN(PTP_TD_EN),
|
||||
@@ -943,6 +965,27 @@ if (COMBINED_MAC_PCS) begin : mac
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.serdes_rx_reset_req(rx_reset_req),
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
.an_en(an_en),
|
||||
.an_restart(an_restart),
|
||||
.an_speedup(an_speedup),
|
||||
.an_timeout_en(an_timeout_en),
|
||||
.an_usxgmii_en(an_usxgmii_en),
|
||||
.an_usxgmii_auto(an_usxgmii_auto),
|
||||
.an_usxgmii_5g(1'b0),
|
||||
.an_intr(an_intr),
|
||||
.an_running(an_running),
|
||||
.an_complete(an_complete),
|
||||
.an_timeout(an_timeout),
|
||||
.an_usxgmii_mode(an_usxgmii_mode),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii),
|
||||
.an_lp_adv_ability(an_lp_adv_ability),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed),
|
||||
.an_res_full_duplex(an_res_full_duplex),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@ export PARAM_QPLL0_EXT_CTRL := 0
|
||||
export PARAM_QPLL1_EXT_CTRL := 0
|
||||
export PARAM_COMBINED_MAC_PCS := 1
|
||||
export PARAM_DATA_W := 64
|
||||
export PARAM_USXGMII_EN := 0
|
||||
export PARAM_DIC_EN := 1
|
||||
export PARAM_PTP_TS_EN := 1
|
||||
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
|
||||
|
||||
@@ -22,7 +22,7 @@ import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.utils import get_time_from_sim_steps
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
@@ -138,6 +138,14 @@ class TB:
|
||||
dut.rx_rst_in.setimmediatevalue([0]*4)
|
||||
dut.tx_rst_in.setimmediatevalue([0]*4)
|
||||
|
||||
dut.an_en.setimmediatevalue([0]*4)
|
||||
dut.an_restart.setimmediatevalue([0]*4)
|
||||
dut.an_speedup.setimmediatevalue([1]*4)
|
||||
dut.an_timeout_en.setimmediatevalue([1]*4)
|
||||
dut.an_usxgmii_en.setimmediatevalue([0]*4)
|
||||
dut.an_usxgmii_auto.setimmediatevalue([1]*4)
|
||||
dut.an_adv_ability_usxgmii.setimmediatevalue([0x1601]*4)
|
||||
|
||||
dut.stat_rx_fifo_drop.setimmediatevalue([0]*4)
|
||||
|
||||
dut.cfg_tx_pad_en.setimmediatevalue([0]*4)
|
||||
@@ -956,6 +964,159 @@ async def run_test_pfc(dut, port=0, ifg=12):
|
||||
await RisingEdge(dut.xcvr_ctrl_clk)
|
||||
|
||||
|
||||
async def run_usxgmii_an(tb, port=0, cfg=0x0001):
|
||||
# link timer scaled by 1000x for faster simulation
|
||||
link_timer = Timer(1.6, 'us')
|
||||
|
||||
dut = tb.dut
|
||||
|
||||
for k in range(10):
|
||||
tb.log.info("AN_RESTART")
|
||||
tb.serdes_sources[port].set_seq_os((0x0000 << 8) | 0x03)
|
||||
|
||||
await link_timer
|
||||
|
||||
tb.log.info("ABILITY_DETECT")
|
||||
tb.serdes_sources[port].set_seq_os(((cfg & ~0x4000) << 8) | 0x03)
|
||||
tb.serdes_sinks[port].get_os()
|
||||
|
||||
lp_cfg = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk[port])
|
||||
lp_cfg = tb.serdes_sinks[port].get_os()[0]
|
||||
if lp_cfg is None:
|
||||
continue
|
||||
if lp_cfg & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg = lp_cfg >> 8
|
||||
if tb.serdes_sinks[port].get_os_match() and lp_cfg != 0:
|
||||
break
|
||||
|
||||
tb.log.info("ACKNOWLEDGE_DETECT")
|
||||
tb.serdes_sources[port].set_seq_os(((cfg | 0x4000) << 8) | 0x03)
|
||||
tb.serdes_sinks[port].get_os()
|
||||
|
||||
lp_cfg_ack = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk[port])
|
||||
lp_cfg_ack = tb.serdes_sinks[port].get_os()[0]
|
||||
if lp_cfg_ack is None:
|
||||
continue
|
||||
if lp_cfg_ack & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg_ack = lp_cfg_ack >> 8
|
||||
if tb.serdes_sinks[port].get_os_match() and lp_cfg_ack & 0x4000:
|
||||
break
|
||||
elif tb.serdes_sinks[port].get_os_match() and lp_cfg_ack == 0:
|
||||
break
|
||||
|
||||
if lp_cfg | 0x4000 != lp_cfg_ack:
|
||||
tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg | 0x4000, lp_cfg_ack)
|
||||
continue
|
||||
|
||||
if lp_cfg_ack == 0:
|
||||
tb.log.warning("AN restart requested")
|
||||
continue
|
||||
|
||||
tb.log.info("COMPLETE_ACKNOWLEDGE")
|
||||
await link_timer
|
||||
|
||||
tb.log.info("IDLE_DETECT")
|
||||
tb.serdes_sources[port].set_seq_os(None)
|
||||
|
||||
await link_timer
|
||||
|
||||
lp_cfg_ack2 = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk[port])
|
||||
if tb.serdes_sinks[port].get_idle_match():
|
||||
break
|
||||
lp_cfg_ack2 = tb.serdes_sinks[port].get_os()[0]
|
||||
if lp_cfg_ack2 is None:
|
||||
continue
|
||||
if lp_cfg_ack2 & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg_ack2 = lp_cfg_ack2 >> 8
|
||||
if tb.serdes_sinks[port].get_os_match() and (lp_cfg_ack2 == 0 or lp_cfg_ack != lp_cfg_ack2):
|
||||
break
|
||||
|
||||
if lp_cfg_ack2 is not None and lp_cfg_ack != lp_cfg_ack2:
|
||||
tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg_ack, lp_cfg_ack2)
|
||||
continue
|
||||
|
||||
if lp_cfg_ack2 == 0:
|
||||
tb.log.warning("AN restart requested")
|
||||
continue
|
||||
|
||||
tb.log.info("AN done")
|
||||
return lp_cfg_ack
|
||||
|
||||
tb.log.warning("AN timed out")
|
||||
tb.serdes_sources[port].set_seq_os(None)
|
||||
return None
|
||||
|
||||
|
||||
async def run_test_usxgmii(dut, port=0):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
dut.an_en[port].value = 1
|
||||
dut.an_restart[port].value = 0
|
||||
dut.an_speedup[port].value = 1
|
||||
dut.an_timeout_en[port].value = 1
|
||||
dut.an_usxgmii_en[port].value = 0
|
||||
dut.an_usxgmii_auto[port].value = 1
|
||||
dut.an_adv_ability_usxgmii[port].value = 0x1601
|
||||
|
||||
await tb.reset()
|
||||
|
||||
tb.log.info("Wait for reset")
|
||||
while int(dut.rx_rst_out[port].value):
|
||||
await RisingEdge(dut.xcvr_ctrl_clk)
|
||||
|
||||
tb.log.info("Wait for block lock")
|
||||
while not int(dut.rx_block_lock[port].value):
|
||||
await RisingEdge(dut.xcvr_ctrl_clk)
|
||||
|
||||
for k in range(100):
|
||||
await RisingEdge(dut.xcvr_ctrl_clk)
|
||||
|
||||
if 1:
|
||||
for x in range(6):
|
||||
cfg1 = 0x0001 | (x << 9) | ((x & 1) << 12) | ((x & 2) << 14)
|
||||
cfg2 = cfg1
|
||||
dut.an_adv_ability_usxgmii[port].value = cfg2
|
||||
|
||||
lp_cfg = await run_usxgmii_an(tb, port, cfg1)
|
||||
|
||||
for k in range(2000):
|
||||
if not dut.an_running[port].value:
|
||||
break
|
||||
await RisingEdge(dut.tx_clk[port])
|
||||
|
||||
assert lp_cfg == cfg2 | 0x4000
|
||||
assert not int(dut.an_running[port].value)
|
||||
assert int(dut.an_complete[port].value)
|
||||
assert not int(dut.an_timeout[port].value)
|
||||
assert int(dut.an_usxgmii_mode[port].value)
|
||||
assert int(dut.an_lp_adv_ability[port].value) == cfg1 | 0x4000
|
||||
assert bool(dut.an_lp_usxgmii_link[port].value) == bool((cfg1 >> 15) & 1)
|
||||
assert int(dut.an_lp_usxgmii_speed[port].value) == (cfg1 >> 9) & 0x7
|
||||
assert bool(dut.an_res_full_duplex[port].value) == bool((cfg1 >> 12) & 1)
|
||||
else:
|
||||
lp_cfg = await run_usxgmii_an(tb, port, 0x9801)
|
||||
|
||||
for k in range(2000):
|
||||
if not dut.an_running[port].value:
|
||||
break
|
||||
await RisingEdge(dut.tx_clk[port])
|
||||
|
||||
assert lp_cfg is None
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(dut.tx_clk[port])
|
||||
|
||||
|
||||
def size_list():
|
||||
return list(range(60, 128)) + [512, 1514, 9214] + [60]*10
|
||||
|
||||
@@ -1002,6 +1163,11 @@ if getattr(cocotb, 'top', None) is not None:
|
||||
factory.add_option("ifg", [12])
|
||||
factory.generate_tests()
|
||||
|
||||
if cocotb.top.USXGMII_EN.value:
|
||||
for test in [run_test_usxgmii]:
|
||||
factory = TestFactory(test)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
@@ -1054,6 +1220,7 @@ def test_taxi_eth_mac_25g_us(request, data_w, combined_mac_pcs, low_latency, dic
|
||||
parameters['QPLL1_EXT_CTRL'] = 0
|
||||
parameters['COMBINED_MAC_PCS'] = combined_mac_pcs
|
||||
parameters['DATA_W'] = data_w
|
||||
parameters['USXGMII_EN'] = int(data_w == 32)
|
||||
parameters['DIC_EN'] = dic_en
|
||||
parameters['PTP_TS_EN'] = 1
|
||||
parameters['PTP_TD_EN'] = parameters['PTP_TS_EN']
|
||||
|
||||
@@ -43,6 +43,7 @@ module test_taxi_eth_mac_25g_us #
|
||||
parameter logic [CNT-1:0] GT_RX_POLARITY = '0,
|
||||
parameter logic COMBINED_MAC_PCS = 1'b1,
|
||||
parameter DATA_W = 64,
|
||||
parameter logic USXGMII_EN = 1'b1,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TD_EN = PTP_TS_EN,
|
||||
@@ -113,6 +114,23 @@ taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_
|
||||
taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl[CNT]();
|
||||
taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) m_axis_rx[CNT]();
|
||||
|
||||
logic an_en[CNT];
|
||||
logic an_restart[CNT];
|
||||
logic an_speedup[CNT];
|
||||
logic an_timeout_en[CNT];
|
||||
logic an_usxgmii_en[CNT];
|
||||
logic an_usxgmii_auto[CNT];
|
||||
logic an_intr[CNT];
|
||||
logic an_running[CNT];
|
||||
logic an_complete[CNT];
|
||||
logic an_timeout[CNT];
|
||||
logic an_usxgmii_mode[CNT];
|
||||
logic [15:0] an_adv_ability_usxgmii[CNT];
|
||||
logic [15:0] an_lp_adv_ability[CNT];
|
||||
logic an_lp_usxgmii_link[CNT];
|
||||
logic [2:0] an_lp_usxgmii_speed[CNT];
|
||||
logic an_res_full_duplex[CNT];
|
||||
|
||||
logic ptp_clk;
|
||||
logic ptp_rst;
|
||||
logic ptp_sample_clk;
|
||||
@@ -266,6 +284,7 @@ taxi_eth_mac_25g_us #(
|
||||
.GT_RX_POLARITY(GT_RX_POLARITY),
|
||||
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
|
||||
.DATA_W(DATA_W),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TD_EN(PTP_TD_EN),
|
||||
@@ -345,6 +364,26 @@ uut (
|
||||
*/
|
||||
.m_axis_rx(m_axis_rx),
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
.an_en(an_en),
|
||||
.an_restart(an_restart),
|
||||
.an_speedup(an_speedup),
|
||||
.an_timeout_en(an_timeout_en),
|
||||
.an_usxgmii_en(an_usxgmii_en),
|
||||
.an_usxgmii_auto(an_usxgmii_auto),
|
||||
.an_intr(an_intr),
|
||||
.an_running(an_running),
|
||||
.an_complete(an_complete),
|
||||
.an_timeout(an_timeout),
|
||||
.an_usxgmii_mode(an_usxgmii_mode),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii),
|
||||
.an_lp_adv_ability(an_lp_adv_ability),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed),
|
||||
.an_res_full_duplex(an_res_full_duplex),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@ export PARAM_DATA_W := 64
|
||||
export PARAM_HDR_W := 2
|
||||
export PARAM_TX_GBX_IF_EN := 1
|
||||
export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN)
|
||||
export PARAM_USXGMII_EN := 0
|
||||
export PARAM_DIC_EN := 1
|
||||
export PARAM_PTP_TS_EN := 1
|
||||
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)
|
||||
|
||||
@@ -22,7 +22,7 @@ import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.utils import get_time_from_sim_steps
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
@@ -106,6 +106,15 @@ class TB:
|
||||
period_ns=self.ptp_clk_period
|
||||
)
|
||||
|
||||
dut.an_en.setimmediatevalue(0)
|
||||
dut.an_restart.setimmediatevalue(0)
|
||||
dut.an_speedup.setimmediatevalue(1)
|
||||
dut.an_timeout_en.setimmediatevalue(1)
|
||||
dut.an_usxgmii_en.setimmediatevalue(0)
|
||||
dut.an_usxgmii_auto.setimmediatevalue(1)
|
||||
dut.an_usxgmii_5g.setimmediatevalue(0)
|
||||
dut.an_adv_ability_usxgmii.setimmediatevalue(0x1601)
|
||||
|
||||
dut.stat_rx_fifo_drop.setimmediatevalue(0)
|
||||
|
||||
dut.cfg_tx_pad_en.setimmediatevalue(0)
|
||||
@@ -850,6 +859,152 @@ async def run_test_pfc(dut, gbx_cfg=None, ifg=12):
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
|
||||
async def run_usxgmii_an(tb, cfg):
|
||||
# link timer scaled by 1000x for faster simulation
|
||||
link_timer = Timer(1.6, 'us')
|
||||
|
||||
dut = tb.dut
|
||||
|
||||
for k in range(10):
|
||||
tb.log.info("AN_RESTART")
|
||||
tb.serdes_source.set_seq_os((0x0000 << 8) | 0x03)
|
||||
|
||||
await link_timer
|
||||
|
||||
tb.log.info("ABILITY_DETECT")
|
||||
tb.serdes_source.set_seq_os(((cfg & ~0x4000) << 8) | 0x03)
|
||||
tb.serdes_sink.get_os()
|
||||
|
||||
lp_cfg = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk)
|
||||
lp_cfg = tb.serdes_sink.get_os()[0]
|
||||
if lp_cfg is None:
|
||||
continue
|
||||
if lp_cfg & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg = lp_cfg >> 8
|
||||
if tb.serdes_sink.get_os_match() and lp_cfg != 0:
|
||||
break
|
||||
|
||||
tb.log.info("ACKNOWLEDGE_DETECT")
|
||||
tb.serdes_source.set_seq_os(((cfg | 0x4000) << 8) | 0x03)
|
||||
tb.serdes_sink.get_os()
|
||||
|
||||
lp_cfg_ack = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk)
|
||||
lp_cfg_ack = tb.serdes_sink.get_os()[0]
|
||||
if lp_cfg_ack is None:
|
||||
continue
|
||||
if lp_cfg_ack & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg_ack = lp_cfg_ack >> 8
|
||||
if tb.serdes_sink.get_os_match() and lp_cfg_ack & 0x4000:
|
||||
break
|
||||
elif tb.serdes_sink.get_os_match() and lp_cfg_ack == 0:
|
||||
break
|
||||
|
||||
if lp_cfg | 0x4000 != lp_cfg_ack:
|
||||
tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg | 0x4000, lp_cfg_ack)
|
||||
continue
|
||||
|
||||
if lp_cfg_ack == 0:
|
||||
tb.log.warning("AN restart requested")
|
||||
continue
|
||||
|
||||
tb.log.info("COMPLETE_ACKNOWLEDGE")
|
||||
await link_timer
|
||||
|
||||
tb.log.info("IDLE_DETECT")
|
||||
tb.serdes_source.set_seq_os(None)
|
||||
|
||||
await link_timer
|
||||
|
||||
lp_cfg_ack2 = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk)
|
||||
if tb.serdes_sink.get_idle_match():
|
||||
break
|
||||
lp_cfg_ack2 = tb.serdes_sink.get_os()[0]
|
||||
if lp_cfg_ack2 is None:
|
||||
continue
|
||||
if lp_cfg_ack2 & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg_ack2 = lp_cfg_ack2 >> 8
|
||||
if tb.serdes_sink.get_os_match() and (lp_cfg_ack2 == 0 or lp_cfg_ack != lp_cfg_ack2):
|
||||
break
|
||||
|
||||
if lp_cfg_ack2 is not None and lp_cfg_ack != lp_cfg_ack2:
|
||||
tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg_ack, lp_cfg_ack2)
|
||||
continue
|
||||
|
||||
if lp_cfg_ack2 == 0:
|
||||
tb.log.warning("AN restart requested")
|
||||
continue
|
||||
|
||||
tb.log.info("AN done")
|
||||
return lp_cfg_ack
|
||||
|
||||
tb.log.warning("AN timed out")
|
||||
tb.serdes_source.set_seq_os(None)
|
||||
return None
|
||||
|
||||
|
||||
async def run_test_usxgmii(dut, gbx_cfg=None):
|
||||
|
||||
tb = TB(dut, gbx_cfg)
|
||||
|
||||
dut.an_en.value = 1
|
||||
dut.an_restart.value = 0
|
||||
dut.an_speedup.value = 1
|
||||
dut.an_timeout_en.value = 1
|
||||
dut.an_usxgmii_en.value = 0
|
||||
dut.an_usxgmii_auto.value = 1
|
||||
dut.an_usxgmii_5g.value = 0
|
||||
dut.an_adv_ability_usxgmii.value = 0x1601
|
||||
|
||||
await tb.reset()
|
||||
|
||||
for k in range(100):
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
if 1:
|
||||
for x in range(6):
|
||||
cfg1 = 0x0001 | (x << 9) | ((x & 1) << 12) | ((x & 2) << 14)
|
||||
cfg2 = cfg1
|
||||
dut.an_adv_ability_usxgmii.value = cfg2
|
||||
|
||||
lp_cfg = await run_usxgmii_an(tb, cfg1)
|
||||
|
||||
for k in range(2000):
|
||||
if not dut.an_running.value:
|
||||
break
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
assert lp_cfg == cfg2 | 0x4000
|
||||
assert not int(dut.an_running.value)
|
||||
assert int(dut.an_complete.value)
|
||||
assert not int(dut.an_timeout.value)
|
||||
assert int(dut.an_usxgmii_mode.value)
|
||||
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
|
||||
assert bool(dut.an_lp_usxgmii_link.value) == bool((cfg1 >> 15) & 1)
|
||||
assert int(dut.an_lp_usxgmii_speed.value) == (cfg1 >> 9) & 0x7
|
||||
assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1)
|
||||
else:
|
||||
lp_cfg = await run_usxgmii_an(tb, 0x9801)
|
||||
|
||||
for k in range(2000):
|
||||
if not dut.an_running.value:
|
||||
break
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
assert lp_cfg is None
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
|
||||
def size_list():
|
||||
return list(range(60, 128)) + [512, 1514, 9214] + [60]*10
|
||||
|
||||
@@ -904,6 +1059,12 @@ if getattr(cocotb, 'top', None) is not None:
|
||||
factory.add_option("gbx_cfg", gbx_cfgs)
|
||||
factory.generate_tests()
|
||||
|
||||
if cocotb.top.USXGMII_EN.value:
|
||||
for test in [run_test_usxgmii]:
|
||||
factory = TestFactory(test)
|
||||
factory.add_option("gbx_cfg", gbx_cfgs)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
@@ -948,6 +1109,7 @@ def test_taxi_eth_mac_phy_10g(request, data_w, ptp_td_en, gbx_en, dic_en, pfc_en
|
||||
parameters['HDR_W'] = 2
|
||||
parameters['TX_GBX_IF_EN'] = gbx_en
|
||||
parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN']
|
||||
parameters['USXGMII_EN'] = int(data_w == 32)
|
||||
parameters['DIC_EN'] = dic_en
|
||||
parameters['PTP_TS_EN'] = 1
|
||||
parameters['PTP_TD_EN'] = ptp_td_en
|
||||
|
||||
@@ -22,6 +22,7 @@ module test_taxi_eth_mac_phy_10g #
|
||||
parameter HDR_W = 2,
|
||||
parameter logic TX_GBX_IF_EN = 1'b0,
|
||||
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
|
||||
parameter logic USXGMII_EN = 1'b1,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
parameter logic PTP_TD_EN = PTP_TS_EN,
|
||||
@@ -76,6 +77,24 @@ logic serdes_rx_hdr_valid;
|
||||
logic serdes_rx_bitslip;
|
||||
logic serdes_rx_reset_req;
|
||||
|
||||
logic an_en;
|
||||
logic an_restart;
|
||||
logic an_speedup;
|
||||
logic an_timeout_en;
|
||||
logic an_usxgmii_en;
|
||||
logic an_usxgmii_auto;
|
||||
logic an_usxgmii_5g;
|
||||
logic an_intr;
|
||||
logic an_running;
|
||||
logic an_complete;
|
||||
logic an_timeout;
|
||||
logic an_usxgmii_mode;
|
||||
logic [15:0] an_adv_ability_usxgmii;
|
||||
logic [15:0] an_lp_adv_ability;
|
||||
logic an_lp_usxgmii_link;
|
||||
logic [2:0] an_lp_usxgmii_speed;
|
||||
logic an_res_full_duplex;
|
||||
|
||||
logic ptp_clk;
|
||||
logic ptp_rst;
|
||||
logic ptp_sample_clk;
|
||||
@@ -208,6 +227,7 @@ taxi_eth_mac_phy_10g #(
|
||||
.HDR_W(HDR_W),
|
||||
.TX_GBX_IF_EN(TX_GBX_IF_EN),
|
||||
.RX_GBX_IF_EN(RX_GBX_IF_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TD_EN(PTP_TD_EN),
|
||||
@@ -266,6 +286,27 @@ uut (
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.serdes_rx_reset_req(serdes_rx_reset_req),
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
.an_en(an_en),
|
||||
.an_restart(an_restart),
|
||||
.an_speedup(an_speedup),
|
||||
.an_timeout_en(an_timeout_en),
|
||||
.an_usxgmii_en(an_usxgmii_en),
|
||||
.an_usxgmii_auto(an_usxgmii_auto),
|
||||
.an_usxgmii_5g(an_usxgmii_5g),
|
||||
.an_intr(an_intr),
|
||||
.an_running(an_running),
|
||||
.an_complete(an_complete),
|
||||
.an_timeout(an_timeout),
|
||||
.an_usxgmii_mode(an_usxgmii_mode),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii),
|
||||
.an_lp_adv_ability(an_lp_adv_ability),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed),
|
||||
.an_res_full_duplex(an_res_full_duplex),
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
|
||||
@@ -36,6 +36,7 @@ export PARAM_DATA_W := 64
|
||||
export PARAM_HDR_W := 2
|
||||
export PARAM_TX_GBX_IF_EN := 1
|
||||
export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN)
|
||||
export PARAM_USXGMII_EN := 0
|
||||
export PARAM_AXIS_DATA_W := $(PARAM_DATA_W)
|
||||
export PARAM_DIC_EN := 1
|
||||
export PARAM_PTP_TS_EN := 1
|
||||
|
||||
@@ -19,7 +19,7 @@ import cocotb_test.simulator
|
||||
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.triggers import RisingEdge, Timer
|
||||
from cocotb.utils import get_time_from_sim_steps
|
||||
from cocotb.regression import TestFactory
|
||||
|
||||
@@ -104,6 +104,15 @@ class TB:
|
||||
period_ns=self.ptp_clk_period
|
||||
)
|
||||
|
||||
dut.an_en.setimmediatevalue(0)
|
||||
dut.an_restart.setimmediatevalue(0)
|
||||
dut.an_speedup.setimmediatevalue(1)
|
||||
dut.an_timeout_en.setimmediatevalue(1)
|
||||
dut.an_usxgmii_en.setimmediatevalue(0)
|
||||
dut.an_usxgmii_auto.setimmediatevalue(1)
|
||||
dut.an_usxgmii_5g.setimmediatevalue(0)
|
||||
dut.an_adv_ability_usxgmii.setimmediatevalue(0x1601)
|
||||
|
||||
dut.cfg_tx_pad_en.setimmediatevalue(0)
|
||||
dut.cfg_tx_min_pkt_len.setimmediatevalue(0)
|
||||
dut.cfg_tx_max_pkt_len.setimmediatevalue(0)
|
||||
@@ -405,6 +414,152 @@ async def run_test_rx_frame_sync(dut, gbx_cfg=None):
|
||||
await RisingEdge(dut.rx_clk)
|
||||
|
||||
|
||||
async def run_usxgmii_an(tb, cfg):
|
||||
# link timer scaled by 1000x for faster simulation
|
||||
link_timer = Timer(1.6, 'us')
|
||||
|
||||
dut = tb.dut
|
||||
|
||||
for k in range(10):
|
||||
tb.log.info("AN_RESTART")
|
||||
tb.serdes_source.set_seq_os((0x0000 << 8) | 0x03)
|
||||
|
||||
await link_timer
|
||||
|
||||
tb.log.info("ABILITY_DETECT")
|
||||
tb.serdes_source.set_seq_os(((cfg & ~0x4000) << 8) | 0x03)
|
||||
tb.serdes_sink.get_os()
|
||||
|
||||
lp_cfg = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk)
|
||||
lp_cfg = tb.serdes_sink.get_os()[0]
|
||||
if lp_cfg is None:
|
||||
continue
|
||||
if lp_cfg & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg = lp_cfg >> 8
|
||||
if tb.serdes_sink.get_os_match() and lp_cfg != 0:
|
||||
break
|
||||
|
||||
tb.log.info("ACKNOWLEDGE_DETECT")
|
||||
tb.serdes_source.set_seq_os(((cfg | 0x4000) << 8) | 0x03)
|
||||
tb.serdes_sink.get_os()
|
||||
|
||||
lp_cfg_ack = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk)
|
||||
lp_cfg_ack = tb.serdes_sink.get_os()[0]
|
||||
if lp_cfg_ack is None:
|
||||
continue
|
||||
if lp_cfg_ack & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg_ack = lp_cfg_ack >> 8
|
||||
if tb.serdes_sink.get_os_match() and lp_cfg_ack & 0x4000:
|
||||
break
|
||||
elif tb.serdes_sink.get_os_match() and lp_cfg_ack == 0:
|
||||
break
|
||||
|
||||
if lp_cfg | 0x4000 != lp_cfg_ack:
|
||||
tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg | 0x4000, lp_cfg_ack)
|
||||
continue
|
||||
|
||||
if lp_cfg_ack == 0:
|
||||
tb.log.warning("AN restart requested")
|
||||
continue
|
||||
|
||||
tb.log.info("COMPLETE_ACKNOWLEDGE")
|
||||
await link_timer
|
||||
|
||||
tb.log.info("IDLE_DETECT")
|
||||
tb.serdes_source.set_seq_os(None)
|
||||
|
||||
await link_timer
|
||||
|
||||
lp_cfg_ack2 = None
|
||||
while True:
|
||||
await RisingEdge(dut.tx_clk)
|
||||
if tb.serdes_sink.get_idle_match():
|
||||
break
|
||||
lp_cfg_ack2 = tb.serdes_sink.get_os()[0]
|
||||
if lp_cfg_ack2 is None:
|
||||
continue
|
||||
if lp_cfg_ack2 & 0xff != 0x03:
|
||||
continue
|
||||
lp_cfg_ack2 = lp_cfg_ack2 >> 8
|
||||
if tb.serdes_sink.get_os_match() and (lp_cfg_ack2 == 0 or lp_cfg_ack != lp_cfg_ack2):
|
||||
break
|
||||
|
||||
if lp_cfg_ack2 is not None and lp_cfg_ack != lp_cfg_ack2:
|
||||
tb.log.warning("AN inconsistent, restarting (0x%04x != 0x%04x)", lp_cfg_ack, lp_cfg_ack2)
|
||||
continue
|
||||
|
||||
if lp_cfg_ack2 == 0:
|
||||
tb.log.warning("AN restart requested")
|
||||
continue
|
||||
|
||||
tb.log.info("AN done")
|
||||
return lp_cfg_ack
|
||||
|
||||
tb.log.warning("AN timed out")
|
||||
tb.serdes_source.set_seq_os(None)
|
||||
return None
|
||||
|
||||
|
||||
async def run_test_usxgmii(dut, gbx_cfg=None):
|
||||
|
||||
tb = TB(dut, gbx_cfg)
|
||||
|
||||
dut.an_en.value = 1
|
||||
dut.an_restart.value = 0
|
||||
dut.an_speedup.value = 1
|
||||
dut.an_timeout_en.value = 1
|
||||
dut.an_usxgmii_en.value = 0
|
||||
dut.an_usxgmii_auto.value = 1
|
||||
dut.an_usxgmii_5g.value = 0
|
||||
dut.an_adv_ability_usxgmii.value = 0x1601
|
||||
|
||||
await tb.reset()
|
||||
|
||||
for k in range(100):
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
if 1:
|
||||
for x in range(6):
|
||||
cfg1 = 0x0001 | (x << 9) | ((x & 1) << 12) | ((x & 2) << 14)
|
||||
cfg2 = cfg1
|
||||
dut.an_adv_ability_usxgmii.value = cfg2
|
||||
|
||||
lp_cfg = await run_usxgmii_an(tb, cfg1)
|
||||
|
||||
for k in range(2000):
|
||||
if not dut.an_running.value:
|
||||
break
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
assert lp_cfg == cfg2 | 0x4000
|
||||
assert not int(dut.an_running.value)
|
||||
assert int(dut.an_complete.value)
|
||||
assert not int(dut.an_timeout.value)
|
||||
assert int(dut.an_usxgmii_mode.value)
|
||||
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
|
||||
assert bool(dut.an_lp_usxgmii_link.value) == bool((cfg1 >> 15) & 1)
|
||||
assert int(dut.an_lp_usxgmii_speed.value) == (cfg1 >> 9) & 0x7
|
||||
assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1)
|
||||
else:
|
||||
lp_cfg = await run_usxgmii_an(tb, 0x9801)
|
||||
|
||||
for k in range(2000):
|
||||
if not dut.an_running.value:
|
||||
break
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
assert lp_cfg is None
|
||||
|
||||
for k in range(10):
|
||||
await RisingEdge(dut.tx_clk)
|
||||
|
||||
|
||||
def size_list():
|
||||
return list(range(60, 128)) + [512, 1514, 9214] + [60]*10
|
||||
|
||||
@@ -445,6 +600,12 @@ if getattr(cocotb, 'top', None) is not None:
|
||||
factory.add_option("gbx_cfg", gbx_cfgs)
|
||||
factory.generate_tests()
|
||||
|
||||
if cocotb.top.USXGMII_EN.value:
|
||||
for test in [run_test_usxgmii]:
|
||||
factory = TestFactory(test)
|
||||
factory.add_option("gbx_cfg", gbx_cfgs)
|
||||
factory.generate_tests()
|
||||
|
||||
|
||||
# cocotb-test
|
||||
|
||||
@@ -488,6 +649,7 @@ def test_taxi_eth_mac_phy_10g_fifo(request, data_w, gbx_en, dic_en):
|
||||
parameters['HDR_W'] = 2
|
||||
parameters['TX_GBX_IF_EN'] = gbx_en
|
||||
parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN']
|
||||
parameters['USXGMII_EN'] = int(data_w == 32)
|
||||
parameters['AXIS_DATA_W'] = parameters['DATA_W']
|
||||
parameters['DIC_EN'] = dic_en
|
||||
parameters['PTP_TS_EN'] = 1
|
||||
|
||||
@@ -22,6 +22,7 @@ module test_taxi_eth_mac_phy_10g_fifo #
|
||||
parameter HDR_W = 2,
|
||||
parameter logic TX_GBX_IF_EN = 1'b0,
|
||||
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
|
||||
parameter logic USXGMII_EN = 1'b1,
|
||||
parameter AXIS_DATA_W = 8,
|
||||
parameter logic DIC_EN = 1'b1,
|
||||
parameter logic PTP_TS_EN = 1'b0,
|
||||
@@ -90,6 +91,24 @@ logic serdes_rx_hdr_valid;
|
||||
logic serdes_rx_bitslip;
|
||||
logic serdes_rx_reset_req;
|
||||
|
||||
logic an_en;
|
||||
logic an_restart;
|
||||
logic an_speedup;
|
||||
logic an_timeout_en;
|
||||
logic an_usxgmii_en;
|
||||
logic an_usxgmii_auto;
|
||||
logic an_usxgmii_5g;
|
||||
logic an_intr;
|
||||
logic an_running;
|
||||
logic an_complete;
|
||||
logic an_timeout;
|
||||
logic an_usxgmii_mode;
|
||||
logic [15:0] an_adv_ability_usxgmii;
|
||||
logic [15:0] an_lp_adv_ability;
|
||||
logic an_lp_usxgmii_link;
|
||||
logic [2:0] an_lp_usxgmii_speed;
|
||||
logic an_res_full_duplex;
|
||||
|
||||
logic ptp_clk;
|
||||
logic ptp_rst;
|
||||
logic ptp_sample_clk;
|
||||
@@ -137,6 +156,7 @@ taxi_eth_mac_phy_10g_fifo #(
|
||||
.HDR_W(HDR_W),
|
||||
.TX_GBX_IF_EN(TX_GBX_IF_EN),
|
||||
.RX_GBX_IF_EN(RX_GBX_IF_EN),
|
||||
.USXGMII_EN(USXGMII_EN),
|
||||
.DIC_EN(DIC_EN),
|
||||
.PTP_TS_EN(PTP_TS_EN),
|
||||
.PTP_TD_EN(PTP_TD_EN),
|
||||
@@ -208,6 +228,27 @@ uut (
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.serdes_rx_reset_req(serdes_rx_reset_req),
|
||||
|
||||
/*
|
||||
* USXGMII autonegotiation
|
||||
*/
|
||||
.an_en(an_en),
|
||||
.an_restart(an_restart),
|
||||
.an_speedup(an_speedup),
|
||||
.an_timeout_en(an_timeout_en),
|
||||
.an_usxgmii_en(an_usxgmii_en),
|
||||
.an_usxgmii_auto(an_usxgmii_auto),
|
||||
.an_usxgmii_5g(an_usxgmii_5g),
|
||||
.an_intr(an_intr),
|
||||
.an_running(an_running),
|
||||
.an_complete(an_complete),
|
||||
.an_timeout(an_timeout),
|
||||
.an_usxgmii_mode(an_usxgmii_mode),
|
||||
.an_adv_ability_usxgmii(an_adv_ability_usxgmii),
|
||||
.an_lp_adv_ability(an_lp_adv_ability),
|
||||
.an_lp_usxgmii_link(an_lp_usxgmii_link),
|
||||
.an_lp_usxgmii_speed(an_lp_usxgmii_speed),
|
||||
.an_res_full_duplex(an_res_full_duplex),
|
||||
|
||||
/*
|
||||
* PTP clock
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user