eth: Implement SGMII AN and auto-switching

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-07-06 17:35:13 -07:00
parent 672fc89b5f
commit 055aa00ae8
17 changed files with 842 additions and 219 deletions

View File

@@ -21,7 +21,8 @@ module taxi_eth_mac_phy_1g_basex #
parameter CTRL_W = (DATA_W/8),
parameter logic TX_GBX_IF_EN = 1'b0,
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -84,13 +85,19 @@ module taxi_eth_mac_phy_1g_basex #
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_sgmii_en = 1'b0,
input wire logic an_sgmii_auto = 1'b1,
output wire logic an_intr,
output wire logic an_running,
output wire logic an_complete,
output wire logic an_timeout,
input wire logic [15:0] an_adv_ability = 16'h0020,
output wire logic an_sgmii_mode,
input wire logic [15:0] an_adv_ability_basex = 16'h0020,
input wire logic [15:0] an_adv_ability_sgmii = 16'h0001,
output wire logic [15:0] an_lp_adv_ability,
output wire logic [1:0] an_lp_remote_fault,
output wire logic an_lp_sgmii_link,
output wire logic [1:0] an_lp_sgmii_speed,
output wire logic an_res_full_duplex,
output wire logic an_res_tx_pause,
output wire logic an_res_rx_pause,
@@ -416,7 +423,8 @@ if (AN_EN) begin : an
);
taxi_eth_phy_1g_basex_an #(
.DATA_W(DATA_W)
.DATA_W(DATA_W),
.SGMII_EN(SGMII_EN)
)
an_inst (
.clk(tx_clk),
@@ -442,13 +450,19 @@ if (AN_EN) begin : an
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause)

View File

@@ -21,7 +21,8 @@ module taxi_eth_mac_phy_1g_basex_fifo #
parameter CTRL_W = (DATA_W/8),
parameter logic TX_GBX_IF_EN = 1'b0,
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -97,13 +98,19 @@ module taxi_eth_mac_phy_1g_basex_fifo #
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_sgmii_en = 1'b0,
input wire logic an_sgmii_auto = 1'b1,
output wire logic an_intr,
output wire logic an_running,
output wire logic an_complete,
output wire logic an_timeout,
input wire logic [15:0] an_adv_ability = 16'h0020,
output wire logic an_sgmii_mode,
input wire logic [15:0] an_adv_ability_basex = 16'h0020,
input wire logic [15:0] an_adv_ability_sgmii = 16'h0001,
output wire logic [15:0] an_lp_adv_ability,
output wire logic [1:0] an_lp_remote_fault,
output wire logic an_lp_sgmii_link,
output wire logic [1:0] an_lp_sgmii_speed,
output wire logic an_res_full_duplex,
output wire logic an_res_tx_pause,
output wire logic an_res_rx_pause,
@@ -316,6 +323,7 @@ taxi_eth_mac_phy_1g_basex #(
.CTRL_W(CTRL_W),
.TX_GBX_IF_EN(TX_GBX_IF_EN),
.RX_GBX_IF_EN(RX_GBX_IF_EN),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
@@ -377,13 +385,19 @@ mac_phy_inst (
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause),

View File

@@ -21,7 +21,8 @@ module taxi_eth_phy_1g_basex #
parameter CTRL_W = (DATA_W/8),
parameter logic TX_GBX_IF_EN = 1'b0,
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic BIT_REVERSE = 1'b0,
parameter logic ENC_8B10B_EN = 1'b0,
parameter logic DEC_8B10B_EN = ENC_8B10B_EN,
@@ -74,13 +75,19 @@ module taxi_eth_phy_1g_basex #
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_sgmii_en = 1'b0,
input wire logic an_sgmii_auto = 1'b1,
output wire logic an_intr,
output wire logic an_running,
output wire logic an_complete,
output wire logic an_timeout,
input wire logic [15:0] an_adv_ability = 16'h0020,
output wire logic an_sgmii_mode,
input wire logic [15:0] an_adv_ability_basex = 16'h0020,
input wire logic [15:0] an_adv_ability_sgmii = 16'h0001,
output wire logic [15:0] an_lp_adv_ability,
output wire logic [1:0] an_lp_remote_fault,
output wire logic an_lp_sgmii_link,
output wire logic [1:0] an_lp_sgmii_speed,
output wire logic an_res_full_duplex,
output wire logic an_res_tx_pause,
output wire logic an_res_rx_pause,
@@ -146,7 +153,8 @@ if (AN_EN) begin : an
);
taxi_eth_phy_1g_basex_an #(
.DATA_W(DATA_W)
.DATA_W(DATA_W),
.SGMII_EN(SGMII_EN)
)
an_inst (
.clk(tx_clk),
@@ -172,13 +180,19 @@ if (AN_EN) begin : an
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause)

View File

@@ -17,7 +17,8 @@ Authors:
*/
module taxi_eth_phy_1g_basex_an #
(
parameter DATA_W = 16
parameter DATA_W = 16,
parameter logic SGMII_EN = 1'b1
)
(
input wire logic clk,
@@ -43,13 +44,19 @@ module taxi_eth_phy_1g_basex_an #
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_sgmii_en = 1'b0,
input wire logic an_sgmii_auto = 1'b1,
output wire logic an_intr,
output wire logic an_running,
output wire logic an_complete,
output wire logic an_timeout,
input wire logic [15:0] an_adv_ability = 16'h0020,
output wire logic an_sgmii_mode,
input wire logic [15:0] an_adv_ability_basex = 16'h0020,
input wire logic [15:0] an_adv_ability_sgmii = 16'h0001,
output wire logic [15:0] an_lp_adv_ability,
output wire logic [1:0] an_lp_remote_fault,
output wire logic an_lp_sgmii_link,
output wire logic [1:0] an_lp_sgmii_speed,
output wire logic an_res_full_duplex,
output wire logic an_res_tx_pause,
output wire logic an_res_rx_pause
@@ -80,6 +87,7 @@ logic [7: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 [1:0] mode_mismatch_cnt_reg = '0, mode_mismatch_cnt_next;
logic [15:0] tx_an_cfg_reg = '0, tx_an_cfg_next;
logic tx_an_cfg_valid_reg = 1'b0, tx_an_cfg_valid_next;
@@ -88,6 +96,7 @@ 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_sgmii_mode_reg = 1'b0, an_sgmii_mode_next;
logic [15:0] an_lp_adv_ability_reg = '0, an_lp_adv_ability_next;
assign tx_an_cfg = tx_an_cfg_reg;
@@ -97,16 +106,19 @@ 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_sgmii_mode = an_sgmii_mode_reg;
assign an_lp_adv_ability = an_lp_adv_ability_reg;
// extract remote fault bits from link partner ability value
assign an_lp_remote_fault = an_lp_adv_ability_reg[13:12];
assign an_lp_remote_fault = an_sgmii_mode_reg ? 2'b00 : an_lp_adv_ability_reg[13:12];
assign an_lp_sgmii_link = an_sgmii_mode_reg ? an_lp_adv_ability_reg[15] : 1'b1;
assign an_lp_sgmii_speed = an_sgmii_mode_reg ? an_lp_adv_ability_reg[11:10] : 2'b10;
// fall back to half duplex only if both ends support it and at least one end does not support full duplex
assign an_res_full_duplex = !((an_adv_ability[6] && an_lp_adv_ability_reg[6]) && (!an_adv_ability[5] || !an_lp_adv_ability_reg[5]));
assign an_res_full_duplex = an_sgmii_mode_reg ? an_lp_adv_ability_reg[12] : !((an_adv_ability_basex[6] && an_lp_adv_ability_reg[6]) && (!an_adv_ability_basex[5] || !an_lp_adv_ability_reg[5]));
// both sides support symmetric pause, or asymmetric pause towards link partner
assign an_res_tx_pause = (an_adv_ability[7] && an_lp_adv_ability_reg[7]) || (an_adv_ability[8:7] == 2'b10 && an_lp_adv_ability_reg[8:7] == 2'b11);
assign an_res_tx_pause = an_sgmii_mode_reg ? 1'b0 : (an_adv_ability_basex[7] && an_lp_adv_ability_reg[7]) || (an_adv_ability_basex[8:7] == 2'b10 && an_lp_adv_ability_reg[8:7] == 2'b11);
// both sides support symmetric pause, or asymmetric pause towards local device
assign an_res_rx_pause = (an_adv_ability[7] && an_lp_adv_ability_reg[7]) || (an_adv_ability[8:7] == 2'b11 && an_lp_adv_ability_reg[8:7] == 2'b10);
assign an_res_rx_pause = an_sgmii_mode_reg ? 1'b0 : (an_adv_ability_basex[7] && an_lp_adv_ability_reg[7]) || (an_adv_ability_basex[8:7] == 2'b11 && an_lp_adv_ability_reg[8:7] == 2'b10);
always_comb begin
state_next = STATE_START;
@@ -115,6 +127,7 @@ always_comb begin
delay_run_next = delay_run_reg;
timeout_cnt_next = timeout_cnt_reg;
timeout_run_next = timeout_run_reg;
mode_mismatch_cnt_next = mode_mismatch_cnt_reg;
tx_an_cfg_next = tx_an_cfg_reg;
tx_an_cfg_valid_next = tx_an_cfg_valid_reg && !tx_an_cfg_ready;
@@ -123,19 +136,21 @@ always_comb begin
an_running_next = an_running_reg;
an_complete_next = an_complete_reg;
an_timeout_next = an_timeout_reg;
an_sgmii_mode_next = an_sgmii_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;
delay_cnt_next = delay_cnt_reg - 1;
end else begin
delay_run_next = 1'b0;
end
end
end else begin
// 10 ms timer
delay_cnt_next = 100;
// 1000BASE-X: 10 ms timer
// SGMII: 1.6 ms timer
delay_cnt_next = an_sgmii_mode_reg ? 16 : 100;
end
if (timeout_run_reg) begin
@@ -159,6 +174,14 @@ always_comb begin
an_timeout_next = 1'b0;
timeout_run_next = 1'b0;
if (an_sgmii_en) begin
an_sgmii_mode_next = 1'b1;
mode_mismatch_cnt_next = '0;
end else if (!an_sgmii_auto) begin
an_sgmii_mode_next = 1'b0;
mode_mismatch_cnt_next = '0;
end
tx_an_cfg_next = '0;
if (an_en) begin
@@ -193,16 +216,35 @@ always_comb begin
end
STATE_ABILITY_DET: begin
// ability detect state - transfer AN ability value with ACK clear
tx_an_cfg_next = an_adv_ability & ~AN_ACK;
tx_an_cfg_next = (an_sgmii_mode_reg ? an_adv_ability_sgmii : an_adv_ability_basex) & ~AN_ACK;
tx_an_cfg_valid_next = 1'b1;
if (rx_an_ability_match && rx_an_cfg != 0) begin
// got ability advertisement from link partner
an_lp_adv_ability_next = rx_an_cfg;
state_next = STATE_ACK_DET;
end else if (!timeout_run_reg) begin
if (rx_an_cfg[0] == an_sgmii_mode_reg) begin
// mode matches
state_next = STATE_ACK_DET;
end else begin
// mode mismatch, restart
if (an_sgmii_auto) begin
// in SGMII auto mode, switch modes after a few mismatches
if (&mode_mismatch_cnt_reg) begin
mode_mismatch_cnt_next = '0;
an_sgmii_mode_next = rx_an_cfg[0];
end else begin
mode_mismatch_cnt_next = mode_mismatch_cnt_reg + 1;
end
end
state_next = STATE_START;
end
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_sgmii_en) begin
an_sgmii_mode_next = 1'b0;
end
mode_mismatch_cnt_next = '0;
state_next = STATE_DONE;
end else begin
state_next = STATE_ABILITY_DET;
@@ -210,7 +252,7 @@ always_comb begin
end
STATE_ACK_DET: begin
// acknowledge detect - wait for ACK from link partner
tx_an_cfg_next = an_adv_ability | AN_ACK;
tx_an_cfg_next = tx_an_cfg_reg | AN_ACK;
tx_an_cfg_valid_next = 1'b1;
if (rx_an_ability_match && rx_an_cfg == 0) begin
@@ -233,7 +275,7 @@ always_comb begin
end
STATE_ACK_CPL: begin
// complete acknowledge - give link partner time to detect our ACK
tx_an_cfg_next = an_adv_ability | AN_ACK;
tx_an_cfg_next = tx_an_cfg_reg | AN_ACK;
tx_an_cfg_valid_next = 1'b1;
if (rx_an_ability_match && rx_an_cfg == 0) begin
@@ -264,6 +306,7 @@ always_comb begin
// AN operation complete
an_running_next = 1'b0;
timeout_run_next = 1'b0;
mode_mismatch_cnt_next = '0;
if (rx_an_ability_match && rx_an_cfg == 0) begin
// restart request from link partner
@@ -289,6 +332,7 @@ always @(posedge clk) begin
delay_run_reg <= delay_run_next;
timeout_cnt_reg <= timeout_cnt_next;
timeout_run_reg <= timeout_run_next;
mode_mismatch_cnt_reg <= mode_mismatch_cnt_next;
tx_an_cfg_reg <= tx_an_cfg_next;
tx_an_cfg_valid_reg <= tx_an_cfg_valid_next;
@@ -297,6 +341,7 @@ always @(posedge clk) begin
an_running_reg <= an_running_next;
an_complete_reg <= an_complete_next;
an_timeout_reg <= an_timeout_next;
an_sgmii_mode_reg <= an_sgmii_mode_next;
an_lp_adv_ability_reg <= an_lp_adv_ability_next;
presc_pulse_reg <= 1'b0;
@@ -316,6 +361,7 @@ always @(posedge clk) begin
delay_run_reg <= 1'b0;
timeout_cnt_reg <= '0;
timeout_run_reg <= 1'b0;
mode_mismatch_cnt_reg <= '0;
tx_an_cfg_valid_reg <= 1'b0;
@@ -323,6 +369,7 @@ always @(posedge clk) begin
an_running_reg <= 1'b0;
an_complete_reg <= 1'b0;
an_timeout_reg <= 1'b0;
an_sgmii_mode_reg <= 1'b0;
end
end

View File

@@ -53,7 +53,8 @@ module taxi_eth_mac_1g_basex_us #
// MAC/PHY parameters
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -138,13 +139,19 @@ module taxi_eth_mac_1g_basex_us #
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_sgmii_en[CNT] = '{CNT{1'b0}},
input wire logic an_sgmii_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],
input wire logic [15:0] an_adv_ability[CNT] = '{CNT{16'h0020}},
output wire logic an_sgmii_mode[CNT],
input wire logic [15:0] an_adv_ability_basex[CNT] = '{CNT{16'h0020}},
input wire logic [15:0] an_adv_ability_sgmii[CNT] = '{CNT{16'h0001}},
output wire logic [15:0] an_lp_adv_ability[CNT],
output wire logic [1:0] an_lp_remote_fault[CNT],
output wire logic an_lp_sgmii_link[CNT],
output wire logic [1:0] an_lp_sgmii_speed[CNT],
output wire logic an_res_full_duplex[CNT],
output wire logic an_res_tx_pause[CNT],
output wire logic an_res_rx_pause[CNT],
@@ -441,6 +448,7 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch
// MAC/PHY parameters
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
@@ -540,13 +548,19 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch
.an_restart(an_restart[n]),
.an_speedup(an_speedup[n]),
.an_timeout_en(an_timeout_en[n]),
.an_sgmii_en(an_sgmii_en[n]),
.an_sgmii_auto(an_sgmii_auto[n]),
.an_intr(an_intr[n]),
.an_running(an_running[n]),
.an_complete(an_complete[n]),
.an_timeout(an_timeout[n]),
.an_adv_ability(an_adv_ability[n]),
.an_sgmii_mode(an_sgmii_mode[n]),
.an_adv_ability_basex(an_adv_ability_basex[n]),
.an_adv_ability_sgmii(an_adv_ability_sgmii[n]),
.an_lp_adv_ability(an_lp_adv_ability[n]),
.an_lp_remote_fault(an_lp_remote_fault[n]),
.an_lp_sgmii_link(an_lp_sgmii_link[n]),
.an_lp_sgmii_speed(an_lp_sgmii_speed[n]),
.an_res_full_duplex(an_res_full_duplex[n]),
.an_res_tx_pause(an_res_tx_pause[n]),
.an_res_rx_pause(an_res_rx_pause[n]),

View File

@@ -52,7 +52,8 @@ module taxi_eth_mac_1g_basex_us_ch #
// MAC/PHY parameters
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -151,13 +152,19 @@ module taxi_eth_mac_1g_basex_us_ch #
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_sgmii_en = 1'b0,
input wire logic an_sgmii_auto = 1'b1,
output wire logic an_intr,
output wire logic an_running,
output wire logic an_complete,
output wire logic an_timeout,
input wire logic [15:0] an_adv_ability = 16'h0020,
output wire logic an_sgmii_mode,
input wire logic [15:0] an_adv_ability_basex = 16'h0020,
input wire logic [15:0] an_adv_ability_sgmii = 16'h0001,
output wire logic [15:0] an_lp_adv_ability,
output wire logic [1:0] an_lp_remote_fault,
output wire logic an_lp_sgmii_link,
output wire logic [1:0] an_lp_sgmii_speed,
output wire logic an_res_full_duplex,
output wire logic an_res_tx_pause,
output wire logic an_res_rx_pause,
@@ -574,6 +581,7 @@ if (COMBINED_MAC_PCS) begin : mac
.CTRL_W(CTRL_W),
.TX_GBX_IF_EN(GBX_EN),
.RX_GBX_IF_EN(GBX_EN),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
@@ -635,13 +643,19 @@ if (COMBINED_MAC_PCS) begin : mac
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause),

View File

@@ -43,7 +43,8 @@ export PARAM_QPLL1_PD := 1
export PARAM_QPLL0_EXT_CTRL := 0
export PARAM_QPLL1_EXT_CTRL := 0
export PARAM_COMBINED_MAC_PCS := 1
export PARAM_AN_EN := 1
export PARAM_SGMII_EN := 1
export PARAM_AN_EN := $(PARAM_SGMII_EN)
export PARAM_DIC_EN := 1
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)

View File

@@ -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
@@ -131,7 +131,10 @@ class TB:
dut.an_restart.setimmediatevalue([0]*4)
dut.an_speedup.setimmediatevalue([1]*4)
dut.an_timeout_en.setimmediatevalue([1]*4)
dut.an_adv_ability.setimmediatevalue([0x0020]*4)
dut.an_sgmii_en.setimmediatevalue([0]*4)
dut.an_sgmii_auto.setimmediatevalue([1]*4)
dut.an_adv_ability_basex.setimmediatevalue([0x0020]*4)
dut.an_adv_ability_sgmii.setimmediatevalue([0x0001]*4)
dut.stat_rx_fifo_drop.setimmediatevalue([0]*4)
@@ -780,7 +783,75 @@ async def run_test_pfc(dut, port=0, ifg=12):
await RisingEdge(dut.xcvr_ctrl_clk)
async def run_test_an(dut, port=0):
async def run_basex_an(tb, port=0, cfg=0x0020, sgmii=False):
# link timer scaled by 1000x for faster simulation
link_timer = Timer(10, 'us')
if sgmii:
link_timer = Timer(1.6, 'us')
dut = tb.dut
for k in range(10):
tb.log.info("AN_RESTART")
tb.serdes_sources[port].set_an_cfg(0x0000)
await link_timer
tb.log.info("ABILITY_DETECT")
tb.serdes_sources[port].set_an_cfg(cfg & ~0x4000)
tb.serdes_sinks[port].get_an_cfg()
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk[port])
lp_cfg = tb.serdes_sinks[port].get_an_cfg()
if tb.serdes_sinks[port].get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_sources[port].set_an_cfg(cfg | 0x4000)
tb.serdes_sinks[port].get_an_cfg()
lp_cfg_ack = None
while True:
await RisingEdge(dut.tx_clk[port])
lp_cfg_ack = tb.serdes_sinks[port].get_an_cfg()
if tb.serdes_sinks[port].get_an_ack_match():
if lp_cfg | 0x4000 == lp_cfg_ack:
break
elif tb.serdes_sinks[port].get_an_ability_match() and lp_cfg_ack is not None and lp_cfg_ack == 0:
break
if lp_cfg | 0x4000 != lp_cfg_ack:
tb.log.warning("AN inconsistent, restarting")
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_an_cfg(None)
await link_timer
while True:
await RisingEdge(dut.tx_clk[port])
if tb.serdes_sinks[port].get_an_idle_match():
break
return lp_cfg_ack
tb.log.warning("AN timed out")
tb.serdes_sources[port].set_an_cfg(None)
return None
async def run_test_an(dut, port=0, sgmii_en=False, sgmii_auto=False):
tb = TB(dut)
@@ -788,7 +859,10 @@ async def run_test_an(dut, port=0):
tb.dut.an_restart[port].value = 0
tb.dut.an_speedup[port].value = 1
tb.dut.an_timeout_en[port].value = 1
tb.dut.an_adv_ability[port].value = 0x0020
tb.dut.an_sgmii_en[port].value = sgmii_en
tb.dut.an_sgmii_auto[port].value = sgmii_auto
tb.dut.an_adv_ability_basex[port].value = 0x0020
tb.dut.an_adv_ability_sgmii[port].value = 0x0001
await tb.reset()
@@ -803,54 +877,92 @@ async def run_test_an(dut, port=0):
for k in range(100):
await RisingEdge(dut.xcvr_ctrl_clk)
tb.log.info("AN_RESTART")
tb.serdes_sources[port].set_an_cfg(0x0000)
tb.log.info("Link partner is 1000BASE-X")
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk[port])
if not sgmii_en:
for x in range(16):
cfg1 = 0x000A | ((x & 3) << 5) | ((x & 3) << 7) | ((x & 3) << 12)
cfg2 = 0x000C | (((x >> 2) & 3) << 5) | (((x >> 2) & 3) << 7) | (((x >> 2) & 3) << 12)
cfg1 = 0x002A
cfg2 = 0x0020
dut.an_adv_ability_basex[port].value = cfg2
tb.log.info("ABILITY_DETECT")
tb.serdes_sources[port].set_an_cfg(0x002A)
lp_cfg = await run_basex_an(tb, port, cfg1, False)
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk[port])
lp_cfg = tb.serdes_sinks[port].get_an_cfg()
if tb.serdes_sinks[port].get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
for k in range(2000):
if not dut.an_running[port].value:
break
await RisingEdge(dut.tx_clk[port])
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability[port].value) & 0xbfff
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 not int(dut.an_sgmii_mode[port].value)
assert int(dut.an_lp_adv_ability[port].value) == cfg1 | 0x4000
assert int(dut.an_lp_remote_fault[port].value) == (cfg1 >> 12) & 0x3
assert bool(dut.an_res_full_duplex[port].value) == ((((cfg1 & cfg2) >> 5) & 0x3) != 0x2)
if ((cfg1 & cfg2) >> 7) & 0x1 == 0x1:
# both ends support symmetric pause
assert bool(dut.an_res_tx_pause[port].value)
assert bool(dut.an_res_rx_pause[port].value)
elif ((cfg1 >> 7) & 3) & 2 == 3 and ((cfg2 >> 7) & 3) & 2 == 2:
# asymmetric towards local
assert not bool(dut.an_res_tx_pause[port].value)
assert bool(dut.an_res_rx_pause[port].value)
elif ((cfg1 >> 7) & 3) & 2 == 2 and ((cfg2 >> 7) & 3) & 2 == 3:
# asymmetric towards partner
assert bool(dut.an_res_tx_pause[port].value)
assert not bool(dut.an_res_rx_pause[port].value)
else:
assert not bool(dut.an_res_tx_pause[port].value)
assert not bool(dut.an_res_rx_pause[port].value)
else:
lp_cfg = await run_basex_an(tb, port, 0x002A, False)
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_sources[port].set_an_cfg(0x402A)
while True:
await RisingEdge(dut.tx_clk[port])
cfg = tb.serdes_sinks[port].get_an_cfg()
if tb.serdes_sinks[port].get_an_ack_match():
if lp_cfg | 0x4000 == cfg:
for k in range(2000):
if not dut.an_running[port].value:
break
await RisingEdge(dut.tx_clk[port])
tb.log.info("COMPLETE_ACKNOWLEDGE")
# link timer
for k in range(1250):
assert lp_cfg is None
for k in range(100):
await RisingEdge(dut.tx_clk[port])
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability[port].value) & 0xbfff
assert int(tb.dut.an_lp_adv_ability[port].value) & 0xbfff == 0x002A
tb.log.info("Link partner is SGMII")
tb.log.info("IDLE_DETECT")
tb.serdes_sources[port].set_an_cfg(None)
if sgmii_en or sgmii_auto:
for x in range(4):
cfg1 = 0x0001 | (x << 10) | ((x & 1) << 12) | ((x & 2) << 14)
cfg2 = cfg1
dut.an_adv_ability_sgmii[port].value = cfg2
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk[port])
lp_cfg = await run_basex_an(tb, port, cfg1, True)
while True:
await RisingEdge(dut.tx_clk[port])
if tb.serdes_sinks[port].get_an_idle_match():
break
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_sgmii_mode[port].value)
assert int(dut.an_lp_adv_ability[port].value) == cfg1 | 0x4000
assert bool(dut.an_lp_sgmii_link[port].value) == bool((cfg1 >> 15) & 1)
assert int(dut.an_lp_sgmii_speed[port].value) == (cfg1 >> 10) & 0x3
assert bool(dut.an_res_full_duplex[port].value) == bool((cfg1 >> 12) & 1)
else:
lp_cfg = await run_basex_an(tb, port, 0x9801, True)
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])
@@ -896,6 +1008,8 @@ if getattr(cocotb, 'top', None) is not None:
if cocotb.top.AN_EN.value:
for test in [run_test_an]:
factory = TestFactory(test)
factory.add_option(("sgmii_en", "sgmii_auto"),
[(False, False), (True, False), (False, True)])
factory.generate_tests()
@@ -947,6 +1061,8 @@ def test_taxi_eth_mac_1g_basex_us(request, low_latency, dic_en, pfc_en):
parameters['QPLL0_EXT_CTRL'] = 0
parameters['QPLL1_EXT_CTRL'] = 0
parameters['COMBINED_MAC_PCS'] = 1
parameters['SGMII_EN'] = 1
parameters['AN_EN'] = parameters['SGMII_EN']
parameters['DIC_EN'] = dic_en
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = parameters['PTP_TS_EN']

View File

@@ -42,7 +42,8 @@ module test_taxi_eth_mac_1g_basex_us #
parameter logic [CNT-1:0] GT_RX_LPM_EN = '0,
parameter logic [CNT-1:0] GT_RX_POLARITY = '0,
parameter logic COMBINED_MAC_PCS = 1'b1,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -116,13 +117,19 @@ logic an_en[CNT];
logic an_restart[CNT];
logic an_speedup[CNT];
logic an_timeout_en[CNT];
logic an_sgmii_en[CNT];
logic an_sgmii_auto[CNT];
logic an_intr[CNT];
logic an_running[CNT];
logic an_complete[CNT];
logic an_timeout[CNT];
logic [15:0] an_adv_ability[CNT];
logic an_sgmii_mode[CNT];
logic [15:0] an_adv_ability_basex[CNT];
logic [15:0] an_adv_ability_sgmii[CNT];
logic [15:0] an_lp_adv_ability[CNT];
logic [1:0] an_lp_remote_fault[CNT];
logic an_lp_sgmii_link[CNT];
logic [1:0] an_lp_sgmii_speed[CNT];
logic an_res_full_duplex[CNT];
logic an_res_tx_pause[CNT];
logic an_res_rx_pause[CNT];
@@ -279,6 +286,7 @@ taxi_eth_mac_1g_basex_us #(
.GT_RX_LPM_EN(GT_RX_LPM_EN),
.GT_RX_POLARITY(GT_RX_POLARITY),
.COMBINED_MAC_PCS(COMBINED_MAC_PCS),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
@@ -364,13 +372,19 @@ uut (
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause),

View File

@@ -35,7 +35,8 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
export PARAM_DATA_W := 16
export PARAM_TX_GBX_IF_EN := 1
export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN)
export PARAM_AN_EN := 1
export PARAM_SGMII_EN := 1
export PARAM_AN_EN := $(PARAM_SGMII_EN)
export PARAM_DIC_EN := 1
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)

View File

@@ -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
@@ -109,7 +109,10 @@ class TB:
dut.an_restart.setimmediatevalue(0)
dut.an_speedup.setimmediatevalue(1)
dut.an_timeout_en.setimmediatevalue(1)
dut.an_adv_ability.setimmediatevalue(0x0020)
dut.an_sgmii_en.setimmediatevalue(0)
dut.an_sgmii_auto.setimmediatevalue(1)
dut.an_adv_ability_basex.setimmediatevalue(0x0020)
dut.an_adv_ability_sgmii.setimmediatevalue(0x0001)
dut.stat_rx_fifo_drop.setimmediatevalue(0)
@@ -709,69 +712,178 @@ async def run_test_pfc(dut, gbx_cfg=None, ifg=12):
await RisingEdge(dut.tx_clk)
async def run_test_an(dut, gbx_cfg=None):
async def run_basex_an(tb, cfg, sgmii=False):
# link timer scaled by 1000x for faster simulation
link_timer = Timer(10, 'us')
if sgmii:
link_timer = Timer(1.6, 'us')
dut = tb.dut
for k in range(10):
tb.log.info("AN_RESTART")
tb.serdes_source.set_an_cfg(0x0000)
await link_timer
tb.log.info("ABILITY_DETECT")
tb.serdes_source.set_an_cfg(cfg & ~0x4000)
tb.serdes_sink.get_an_cfg()
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_source.set_an_cfg(cfg | 0x4000)
tb.serdes_sink.get_an_cfg()
lp_cfg_ack = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg_ack = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ack_match():
if lp_cfg | 0x4000 == lp_cfg_ack:
break
elif tb.serdes_sink.get_an_ability_match() and lp_cfg_ack is not None and lp_cfg_ack == 0:
break
if lp_cfg | 0x4000 != lp_cfg_ack:
tb.log.warning("AN inconsistent, restarting")
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_an_cfg(None)
await link_timer
while True:
await RisingEdge(dut.tx_clk)
if tb.serdes_sink.get_an_idle_match():
break
return lp_cfg_ack
tb.log.warning("AN timed out")
tb.serdes_source.set_an_cfg(None)
return None
async def run_test_an(dut, gbx_cfg=None, sgmii_en=False, sgmii_auto=False):
tb = TB(dut, gbx_cfg)
tb.dut.an_en.value = 1
tb.dut.an_restart.value = 0
tb.dut.an_speedup.value = 1
tb.dut.an_timeout_en.value = 1
tb.dut.an_adv_ability.value = 0x0020
dut.an_en.value = 1
dut.an_restart.value = 0
dut.an_speedup.value = 1
dut.an_timeout_en.value = 1
dut.an_sgmii_en.value = sgmii_en
dut.an_sgmii_auto.value = sgmii_auto
dut.an_adv_ability_basex.value = 0x0020
dut.an_adv_ability_sgmii.value = 0x0001
await tb.reset()
for k in range(100):
await RisingEdge(dut.tx_clk)
tb.log.info("AN_RESTART")
tb.serdes_source.set_an_cfg(0x0000)
tb.log.info("Link partner is 1000BASE-X")
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk)
if not sgmii_en:
for x in range(16):
cfg1 = 0x000A | ((x & 3) << 5) | ((x & 3) << 7) | ((x & 3) << 12)
cfg2 = 0x000C | (((x >> 2) & 3) << 5) | (((x >> 2) & 3) << 7) | (((x >> 2) & 3) << 12)
cfg1 = 0x002A
cfg2 = 0x0020
dut.an_adv_ability_basex.value = cfg2
tb.log.info("ABILITY_DETECT")
tb.serdes_source.set_an_cfg(0x002A)
lp_cfg = await run_basex_an(tb, cfg1, False)
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
for k in range(2000):
if not dut.an_running.value:
break
await RisingEdge(dut.tx_clk)
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff
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 not int(dut.an_sgmii_mode.value)
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
assert int(dut.an_lp_remote_fault.value) == (cfg1 >> 12) & 0x3
assert bool(dut.an_res_full_duplex.value) == ((((cfg1 & cfg2) >> 5) & 0x3) != 0x2)
if ((cfg1 & cfg2) >> 7) & 0x1 == 0x1:
# both ends support symmetric pause
assert bool(dut.an_res_tx_pause.value)
assert bool(dut.an_res_rx_pause.value)
elif ((cfg1 >> 7) & 3) & 2 == 3 and ((cfg2 >> 7) & 3) & 2 == 2:
# asymmetric towards local
assert not bool(dut.an_res_tx_pause.value)
assert bool(dut.an_res_rx_pause.value)
elif ((cfg1 >> 7) & 3) & 2 == 2 and ((cfg2 >> 7) & 3) & 2 == 3:
# asymmetric towards partner
assert bool(dut.an_res_tx_pause.value)
assert not bool(dut.an_res_rx_pause.value)
else:
assert not bool(dut.an_res_tx_pause.value)
assert not bool(dut.an_res_rx_pause.value)
else:
lp_cfg = await run_basex_an(tb, 0x002A, False)
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_source.set_an_cfg(0x402A)
while True:
await RisingEdge(dut.tx_clk)
cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ack_match():
if lp_cfg | 0x4000 == cfg:
for k in range(2000):
if not dut.an_running.value:
break
await RisingEdge(dut.tx_clk)
tb.log.info("COMPLETE_ACKNOWLEDGE")
# link timer
for k in range(1250):
assert lp_cfg is None
for k in range(100):
await RisingEdge(dut.tx_clk)
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff
assert int(tb.dut.an_lp_adv_ability.value) & 0xbfff == 0x002A
tb.log.info("Link partner is SGMII")
tb.log.info("IDLE_DETECT")
tb.serdes_source.set_an_cfg(None)
if sgmii_en or sgmii_auto:
for x in range(4):
cfg1 = 0x0001 | (x << 10) | ((x & 1) << 12) | ((x & 2) << 14)
cfg2 = cfg1
dut.an_adv_ability_sgmii.value = cfg2
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk)
lp_cfg = await run_basex_an(tb, cfg1, True)
while True:
await RisingEdge(dut.tx_clk)
if tb.serdes_sink.get_an_idle_match():
break
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_sgmii_mode.value)
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
assert bool(dut.an_lp_sgmii_link.value) == bool((cfg1 >> 15) & 1)
assert int(dut.an_lp_sgmii_speed.value) == (cfg1 >> 10) & 0x3
assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1)
else:
lp_cfg = await run_basex_an(tb, 0x9801, True)
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)
@@ -823,6 +935,8 @@ if getattr(cocotb, 'top', None) is not None:
for test in [run_test_an]:
factory = TestFactory(test)
factory.add_option("gbx_cfg", gbx_cfgs)
factory.add_option(("sgmii_en", "sgmii_auto"),
[(False, False), (True, False), (False, True)])
factory.generate_tests()
@@ -868,7 +982,8 @@ def test_taxi_eth_mac_phy_1g_basex(request, data_w, ptp_td_en, gbx_en, dic_en, p
parameters['DATA_W'] = data_w
parameters['TX_GBX_IF_EN'] = gbx_en
parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN']
parameters['AN_EN'] = 1
parameters['SGMII_EN'] = 1
parameters['AN_EN'] = parameters['SGMII_EN']
parameters['DIC_EN'] = dic_en
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = ptp_td_en

View File

@@ -22,7 +22,8 @@ module test_taxi_eth_mac_phy_1g_basex #
parameter CTRL_W = DATA_W/8,
parameter logic TX_GBX_IF_EN = 1'b0,
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -78,13 +79,19 @@ logic an_en;
logic an_restart;
logic an_speedup;
logic an_timeout_en;
logic an_sgmii_en;
logic an_sgmii_auto;
logic an_intr;
logic an_running;
logic an_complete;
logic an_timeout;
logic [15:0] an_adv_ability;
logic an_sgmii_mode;
logic [15:0] an_adv_ability_basex;
logic [15:0] an_adv_ability_sgmii;
logic [15:0] an_lp_adv_ability;
logic [1:0] an_lp_remote_fault;
logic an_lp_sgmii_link;
logic [1:0] an_lp_sgmii_speed;
logic an_res_full_duplex;
logic an_res_tx_pause;
logic an_res_rx_pause;
@@ -221,6 +228,7 @@ taxi_eth_mac_phy_1g_basex #(
.CTRL_W(CTRL_W),
.TX_GBX_IF_EN(TX_GBX_IF_EN),
.RX_GBX_IF_EN(RX_GBX_IF_EN),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
@@ -284,13 +292,19 @@ uut (
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause),

View File

@@ -36,7 +36,8 @@ export PARAM_DATA_W := 16
export PARAM_TX_GBX_IF_EN := 1
export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN)
export PARAM_AXIS_DATA_W := $(PARAM_DATA_W)
export PARAM_AN_EN := 1
export PARAM_SGMII_EN := 1
export PARAM_AN_EN := $(PARAM_SGMII_EN)
export PARAM_DIC_EN := 1
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TD_EN := $(PARAM_PTP_TS_EN)

View File

@@ -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
@@ -107,7 +107,10 @@ class TB:
dut.an_restart.setimmediatevalue(0)
dut.an_speedup.setimmediatevalue(1)
dut.an_timeout_en.setimmediatevalue(1)
dut.an_adv_ability.setimmediatevalue(0x0020)
dut.an_sgmii_en.setimmediatevalue(0)
dut.an_sgmii_auto.setimmediatevalue(1)
dut.an_adv_ability_basex.setimmediatevalue(0x0020)
dut.an_adv_ability_sgmii.setimmediatevalue(0x0001)
dut.cfg_tx_pad_en.setimmediatevalue(0)
dut.cfg_tx_min_pkt_len.setimmediatevalue(0)
@@ -268,69 +271,178 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
await RisingEdge(dut.logic_clk)
async def run_test_an(dut, gbx_cfg=None):
async def run_basex_an(tb, cfg, sgmii=False):
# link timer scaled by 1000x for faster simulation
link_timer = Timer(10, 'us')
if sgmii:
link_timer = Timer(1.6, 'us')
dut = tb.dut
for k in range(10):
tb.log.info("AN_RESTART")
tb.serdes_source.set_an_cfg(0x0000)
await link_timer
tb.log.info("ABILITY_DETECT")
tb.serdes_source.set_an_cfg(cfg & ~0x4000)
tb.serdes_sink.get_an_cfg()
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_source.set_an_cfg(cfg | 0x4000)
tb.serdes_sink.get_an_cfg()
lp_cfg_ack = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg_ack = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ack_match():
if lp_cfg | 0x4000 == lp_cfg_ack:
break
elif tb.serdes_sink.get_an_ability_match() and lp_cfg_ack is not None and lp_cfg_ack == 0:
break
if lp_cfg | 0x4000 != lp_cfg_ack:
tb.log.warning("AN inconsistent, restarting")
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_an_cfg(None)
await link_timer
while True:
await RisingEdge(dut.tx_clk)
if tb.serdes_sink.get_an_idle_match():
break
return lp_cfg_ack
tb.log.warning("AN timed out")
tb.serdes_source.set_an_cfg(None)
return None
async def run_test_an(dut, gbx_cfg=None, sgmii_en=False, sgmii_auto=False):
tb = TB(dut, gbx_cfg)
tb.dut.an_en.value = 1
tb.dut.an_restart.value = 0
tb.dut.an_speedup.value = 1
tb.dut.an_timeout_en.value = 1
tb.dut.an_adv_ability.value = 0x0020
dut.an_en.value = 1
dut.an_restart.value = 0
dut.an_speedup.value = 1
dut.an_timeout_en.value = 1
dut.an_sgmii_en.value = sgmii_en
dut.an_sgmii_auto.value = sgmii_auto
dut.an_adv_ability_basex.value = 0x0020
dut.an_adv_ability_sgmii.value = 0x0001
await tb.reset()
for k in range(100):
await RisingEdge(dut.tx_clk)
tb.log.info("AN_RESTART")
tb.serdes_source.set_an_cfg(0x0000)
tb.log.info("Link partner is 1000BASE-X")
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk)
if not sgmii_en:
for x in range(16):
cfg1 = 0x000A | ((x & 3) << 5) | ((x & 3) << 7) | ((x & 3) << 12)
cfg2 = 0x000C | (((x >> 2) & 3) << 5) | (((x >> 2) & 3) << 7) | (((x >> 2) & 3) << 12)
cfg1 = 0x002A
cfg2 = 0x0020
dut.an_adv_ability_basex.value = cfg2
tb.log.info("ABILITY_DETECT")
tb.serdes_source.set_an_cfg(0x002A)
lp_cfg = await run_basex_an(tb, cfg1, False)
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
for k in range(2000):
if not dut.an_running.value:
break
await RisingEdge(dut.tx_clk)
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff
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 not int(dut.an_sgmii_mode.value)
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
assert int(dut.an_lp_remote_fault.value) == (cfg1 >> 12) & 0x3
assert bool(dut.an_res_full_duplex.value) == ((((cfg1 & cfg2) >> 5) & 0x3) != 0x2)
if ((cfg1 & cfg2) >> 7) & 0x1 == 0x1:
# both ends support symmetric pause
assert bool(dut.an_res_tx_pause.value)
assert bool(dut.an_res_rx_pause.value)
elif ((cfg1 >> 7) & 3) & 2 == 3 and ((cfg2 >> 7) & 3) & 2 == 2:
# asymmetric towards local
assert not bool(dut.an_res_tx_pause.value)
assert bool(dut.an_res_rx_pause.value)
elif ((cfg1 >> 7) & 3) & 2 == 2 and ((cfg2 >> 7) & 3) & 2 == 3:
# asymmetric towards partner
assert bool(dut.an_res_tx_pause.value)
assert not bool(dut.an_res_rx_pause.value)
else:
assert not bool(dut.an_res_tx_pause.value)
assert not bool(dut.an_res_rx_pause.value)
else:
lp_cfg = await run_basex_an(tb, 0x002A, False)
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_source.set_an_cfg(0x402A)
while True:
await RisingEdge(dut.tx_clk)
cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ack_match():
if lp_cfg | 0x4000 == cfg:
for k in range(2000):
if not dut.an_running.value:
break
await RisingEdge(dut.tx_clk)
tb.log.info("COMPLETE_ACKNOWLEDGE")
# link timer
for k in range(1250):
assert lp_cfg is None
for k in range(100):
await RisingEdge(dut.tx_clk)
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff
assert int(tb.dut.an_lp_adv_ability.value) & 0xbfff == 0x002A
tb.log.info("Link partner is SGMII")
tb.log.info("IDLE_DETECT")
tb.serdes_source.set_an_cfg(None)
if sgmii_en or sgmii_auto:
for x in range(4):
cfg1 = 0x0001 | (x << 10) | ((x & 1) << 12) | ((x & 2) << 14)
cfg2 = cfg1
dut.an_adv_ability_sgmii.value = cfg2
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk)
lp_cfg = await run_basex_an(tb, cfg1, True)
while True:
await RisingEdge(dut.tx_clk)
if tb.serdes_sink.get_an_idle_match():
break
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_sgmii_mode.value)
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
assert bool(dut.an_lp_sgmii_link.value) == bool((cfg1 >> 15) & 1)
assert int(dut.an_lp_sgmii_speed.value) == (cfg1 >> 10) & 0x3
assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1)
else:
lp_cfg = await run_basex_an(tb, 0x9801, True)
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)
@@ -368,6 +480,8 @@ if getattr(cocotb, 'top', None) is not None:
for test in [run_test_an]:
factory = TestFactory(test)
factory.add_option("gbx_cfg", gbx_cfgs)
factory.add_option(("sgmii_en", "sgmii_auto"),
[(False, False), (True, False), (False, True)])
factory.generate_tests()
@@ -413,7 +527,8 @@ def test_taxi_eth_mac_phy_1g_basex_fifo(request, data_w, gbx_en, dic_en):
parameters['TX_GBX_IF_EN'] = gbx_en
parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN']
parameters['AXIS_DATA_W'] = parameters['DATA_W']
parameters['AN_EN'] = 1
parameters['SGMII_EN'] = 1
parameters['AN_EN'] = parameters['SGMII_EN']
parameters['DIC_EN'] = dic_en
parameters['PTP_TS_EN'] = 1
parameters['PTP_TD_EN'] = parameters['PTP_TS_EN']

View File

@@ -23,7 +23,8 @@ module test_taxi_eth_mac_phy_1g_basex_fifo #
parameter logic TX_GBX_IF_EN = 1'b0,
parameter logic RX_GBX_IF_EN = TX_GBX_IF_EN,
parameter AXIS_DATA_W = 8,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TD_EN = PTP_TS_EN,
@@ -92,13 +93,19 @@ logic an_en;
logic an_restart;
logic an_speedup;
logic an_timeout_en;
logic an_sgmii_en;
logic an_sgmii_auto;
logic an_intr;
logic an_running;
logic an_complete;
logic an_timeout;
logic [15:0] an_adv_ability;
logic an_sgmii_mode;
logic [15:0] an_adv_ability_basex;
logic [15:0] an_adv_ability_sgmii;
logic [15:0] an_lp_adv_ability;
logic [1:0] an_lp_remote_fault;
logic an_lp_sgmii_link;
logic [1:0] an_lp_sgmii_speed;
logic an_res_full_duplex;
logic an_res_tx_pause;
logic an_res_rx_pause;
@@ -150,6 +157,7 @@ taxi_eth_mac_phy_1g_basex_fifo #(
.CTRL_W(CTRL_W),
.TX_GBX_IF_EN(TX_GBX_IF_EN),
.RX_GBX_IF_EN(RX_GBX_IF_EN),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
@@ -226,13 +234,19 @@ uut (
.an_restart(an_restart),
.an_speedup(an_speedup),
.an_timeout_en(an_timeout_en),
.an_sgmii_en(an_sgmii_en),
.an_sgmii_auto(an_sgmii_auto),
.an_intr(an_intr),
.an_running(an_running),
.an_complete(an_complete),
.an_timeout(an_timeout),
.an_adv_ability(an_adv_ability),
.an_sgmii_mode(an_sgmii_mode),
.an_adv_ability_basex(an_adv_ability_basex),
.an_adv_ability_sgmii(an_adv_ability_sgmii),
.an_lp_adv_ability(an_lp_adv_ability),
.an_lp_remote_fault(an_lp_remote_fault),
.an_lp_sgmii_link(an_lp_sgmii_link),
.an_lp_sgmii_speed(an_lp_sgmii_speed),
.an_res_full_duplex(an_res_full_duplex),
.an_res_tx_pause(an_res_tx_pause),
.an_res_rx_pause(an_res_rx_pause),

View File

@@ -35,7 +35,8 @@ export PARAM_DATA_W := 16
export PARAM_CTRL_W := $(shell expr $(PARAM_DATA_W) / 8 )
export PARAM_TX_GBX_IF_EN := 0
export PARAM_RX_GBX_IF_EN := $(PARAM_TX_GBX_IF_EN)
export PARAM_AN_EN := "1'b1"
export PARAM_SGMII_EN := "1'b1"
export PARAM_AN_EN := $(PARAM_SGMII_EN)
export PARAM_BIT_REVERSE := "1'b0"
export PARAM_ENC_8B10B_EN := "1'b0"
export PARAM_DEC_8B10B_EN := $(PARAM_ENC_8B10B_EN)

View File

@@ -19,7 +19,7 @@ import cocotb_test.simulator
import pytest
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from cocotb.triggers import RisingEdge, Timer
from cocotb.regression import TestFactory
from cocotbext.eth import GmiiSource, GmiiSink, GmiiFrame
@@ -79,7 +79,10 @@ class TB:
dut.an_restart.setimmediatevalue(0)
dut.an_speedup.setimmediatevalue(1)
dut.an_timeout_en.setimmediatevalue(1)
dut.an_adv_ability.setimmediatevalue(0x0020)
dut.an_sgmii_en.setimmediatevalue(0)
dut.an_sgmii_auto.setimmediatevalue(1)
dut.an_adv_ability_basex.setimmediatevalue(0x0020)
dut.an_adv_ability_sgmii.setimmediatevalue(0x0001)
dut.cfg_tx_prbs31_enable.setimmediatevalue(0)
dut.cfg_rx_prbs31_enable.setimmediatevalue(0)
@@ -160,69 +163,178 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
await RisingEdge(dut.tx_clk)
async def run_test_an(dut):
async def run_basex_an(tb, cfg, sgmii=False):
# link timer scaled by 1000x for faster simulation
link_timer = Timer(10, 'us')
if sgmii:
link_timer = Timer(1.6, 'us')
dut = tb.dut
for k in range(10):
tb.log.info("AN_RESTART")
tb.serdes_source.set_an_cfg(0x0000)
await link_timer
tb.log.info("ABILITY_DETECT")
tb.serdes_source.set_an_cfg(cfg & ~0x4000)
tb.serdes_sink.get_an_cfg()
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_source.set_an_cfg(cfg | 0x4000)
tb.serdes_sink.get_an_cfg()
lp_cfg_ack = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg_ack = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ack_match():
if lp_cfg | 0x4000 == lp_cfg_ack:
break
elif tb.serdes_sink.get_an_ability_match() and lp_cfg_ack is not None and lp_cfg_ack == 0:
break
if lp_cfg | 0x4000 != lp_cfg_ack:
tb.log.warning("AN inconsistent, restarting")
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_an_cfg(None)
await link_timer
while True:
await RisingEdge(dut.tx_clk)
if tb.serdes_sink.get_an_idle_match():
break
return lp_cfg_ack
tb.log.warning("AN timed out")
tb.serdes_source.set_an_cfg(None)
return None
async def run_test_an(dut, sgmii_en=False, sgmii_auto=False):
tb = TB(dut)
tb.dut.an_en.value = 1
tb.dut.an_restart.value = 0
tb.dut.an_speedup.value = 1
tb.dut.an_timeout_en.value = 1
tb.dut.an_adv_ability.value = 0x0020
dut.an_en.value = 1
dut.an_restart.value = 0
dut.an_speedup.value = 1
dut.an_timeout_en.value = 1
dut.an_sgmii_en.value = sgmii_en
dut.an_sgmii_auto.value = sgmii_auto
dut.an_adv_ability_basex.value = 0x0020
dut.an_adv_ability_sgmii.value = 0x0001
await tb.reset()
for k in range(100):
await RisingEdge(dut.tx_clk)
tb.log.info("AN_RESTART")
tb.serdes_source.set_an_cfg(0x0000)
tb.log.info("Link partner is 1000BASE-X")
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk)
if not sgmii_en:
for x in range(16):
cfg1 = 0x000A | ((x & 3) << 5) | ((x & 3) << 7) | ((x & 3) << 12)
cfg2 = 0x000C | (((x >> 2) & 3) << 5) | (((x >> 2) & 3) << 7) | (((x >> 2) & 3) << 12)
cfg1 = 0x002A
cfg2 = 0x0020
dut.an_adv_ability_basex.value = cfg2
tb.log.info("ABILITY_DETECT")
tb.serdes_source.set_an_cfg(0x002A)
lp_cfg = await run_basex_an(tb, cfg1, False)
lp_cfg = None
while True:
await RisingEdge(dut.tx_clk)
lp_cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ability_match() and lp_cfg is not None and lp_cfg != 0:
break
for k in range(2000):
if not dut.an_running.value:
break
await RisingEdge(dut.tx_clk)
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff
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 not int(dut.an_sgmii_mode.value)
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
assert int(dut.an_lp_remote_fault.value) == (cfg1 >> 12) & 0x3
assert bool(dut.an_res_full_duplex.value) == ((((cfg1 & cfg2) >> 5) & 0x3) != 0x2)
if ((cfg1 & cfg2) >> 7) & 0x1 == 0x1:
# both ends support symmetric pause
assert bool(dut.an_res_tx_pause.value)
assert bool(dut.an_res_rx_pause.value)
elif ((cfg1 >> 7) & 3) & 2 == 3 and ((cfg2 >> 7) & 3) & 2 == 2:
# asymmetric towards local
assert not bool(dut.an_res_tx_pause.value)
assert bool(dut.an_res_rx_pause.value)
elif ((cfg1 >> 7) & 3) & 2 == 2 and ((cfg2 >> 7) & 3) & 2 == 3:
# asymmetric towards partner
assert bool(dut.an_res_tx_pause.value)
assert not bool(dut.an_res_rx_pause.value)
else:
assert not bool(dut.an_res_tx_pause.value)
assert not bool(dut.an_res_rx_pause.value)
else:
lp_cfg = await run_basex_an(tb, 0x002A, False)
tb.log.info("ACKNOWLEDGE_DETECT")
tb.serdes_source.set_an_cfg(0x402A)
while True:
await RisingEdge(dut.tx_clk)
cfg = tb.serdes_sink.get_an_cfg()
if tb.serdes_sink.get_an_ack_match():
if lp_cfg | 0x4000 == cfg:
for k in range(2000):
if not dut.an_running.value:
break
await RisingEdge(dut.tx_clk)
tb.log.info("COMPLETE_ACKNOWLEDGE")
# link timer
for k in range(1250):
assert lp_cfg is None
for k in range(100):
await RisingEdge(dut.tx_clk)
assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff
assert int(tb.dut.an_lp_adv_ability) & 0xbfff == 0x002A
tb.log.info("Link partner is SGMII")
tb.log.info("IDLE_DETECT")
tb.serdes_source.set_an_cfg(None)
if sgmii_en or sgmii_auto:
for x in range(4):
cfg1 = 0x0001 | (x << 10) | ((x & 1) << 12) | ((x & 2) << 14)
cfg2 = cfg1
dut.an_adv_ability_sgmii.value = cfg2
# link timer
for k in range(1250):
await RisingEdge(dut.tx_clk)
lp_cfg = await run_basex_an(tb, cfg1, True)
while True:
await RisingEdge(dut.tx_clk)
if tb.serdes_sink.get_an_idle_match():
break
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_sgmii_mode.value)
assert int(dut.an_lp_adv_ability.value) == cfg1 | 0x4000
assert bool(dut.an_lp_sgmii_link.value) == bool((cfg1 >> 15) & 1)
assert int(dut.an_lp_sgmii_speed.value) == (cfg1 >> 10) & 0x3
assert bool(dut.an_res_full_duplex.value) == bool((cfg1 >> 12) & 1)
else:
lp_cfg = await run_basex_an(tb, 0x9801, True)
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)
@@ -253,6 +365,7 @@ if getattr(cocotb, 'top', None) is not None:
if cocotb.top.AN_EN.value:
for test in [run_test_an]:
factory = TestFactory(test)
factory.add_option(("sgmii_en", "sgmii_auto"), [(False, False), (True, False), (False, True)])
factory.generate_tests()
@@ -296,7 +409,8 @@ def test_taxi_eth_phy_1g_basex(request, data_w):
parameters['CTRL_W'] = parameters['DATA_W'] // 8
parameters['TX_GBX_IF_EN'] = 0
parameters['RX_GBX_IF_EN'] = parameters['TX_GBX_IF_EN']
parameters['AN_EN'] = "1'b1"
parameters['SGMII_EN'] = "1'b1"
parameters['AN_EN'] = parameters['SGMII_EN']
parameters['BIT_REVERSE'] = "1'b0"
parameters['ENC_8B10B_EN'] = "1'b0"
parameters['DEC_8B10B_EN'] = parameters['ENC_8B10B_EN']