mirror of
https://github.com/fpganinja/taxi.git
synced 2026-08-05 06:51:24 -07:00
eth: Implement SGMII AN and auto-switching
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
Reference in New Issue
Block a user