diff --git a/src/eth/rtl/taxi_eth_mac_phy_1g_basex.sv b/src/eth/rtl/taxi_eth_mac_phy_1g_basex.sv index 5381b5b..4dc2db8 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_1g_basex.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_1g_basex.sv @@ -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) diff --git a/src/eth/rtl/taxi_eth_mac_phy_1g_basex_fifo.sv b/src/eth/rtl/taxi_eth_mac_phy_1g_basex_fifo.sv index 323e263..7cc1b1c 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_1g_basex_fifo.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_1g_basex_fifo.sv @@ -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), diff --git a/src/eth/rtl/taxi_eth_phy_1g_basex.sv b/src/eth/rtl/taxi_eth_phy_1g_basex.sv index dffe0b0..c74bdc1 100644 --- a/src/eth/rtl/taxi_eth_phy_1g_basex.sv +++ b/src/eth/rtl/taxi_eth_phy_1g_basex.sv @@ -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) diff --git a/src/eth/rtl/taxi_eth_phy_1g_basex_an.sv b/src/eth/rtl/taxi_eth_phy_1g_basex_an.sv index 06c2c69..bc05c06 100644 --- a/src/eth/rtl/taxi_eth_phy_1g_basex_an.sv +++ b/src/eth/rtl/taxi_eth_phy_1g_basex_an.sv @@ -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 diff --git a/src/eth/rtl/us/taxi_eth_mac_1g_basex_us.sv b/src/eth/rtl/us/taxi_eth_mac_1g_basex_us.sv index fa96d72..d4983a5 100644 --- a/src/eth/rtl/us/taxi_eth_mac_1g_basex_us.sv +++ b/src/eth/rtl/us/taxi_eth_mac_1g_basex_us.sv @@ -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]), diff --git a/src/eth/rtl/us/taxi_eth_mac_1g_basex_us_ch.sv b/src/eth/rtl/us/taxi_eth_mac_1g_basex_us_ch.sv index 6107bda..542d830 100644 --- a/src/eth/rtl/us/taxi_eth_mac_1g_basex_us_ch.sv +++ b/src/eth/rtl/us/taxi_eth_mac_1g_basex_us_ch.sv @@ -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), diff --git a/src/eth/tb/taxi_eth_mac_1g_basex_us/Makefile b/src/eth/tb/taxi_eth_mac_1g_basex_us/Makefile index 089e068..6e06f4c 100644 --- a/src/eth/tb/taxi_eth_mac_1g_basex_us/Makefile +++ b/src/eth/tb/taxi_eth_mac_1g_basex_us/Makefile @@ -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) diff --git a/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.py b/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.py index a677be0..6129a49 100644 --- a/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.py +++ b/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.py @@ -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'] diff --git a/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.sv b/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.sv index 89f3f8b..50eadef 100644 --- a/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.sv +++ b/src/eth/tb/taxi_eth_mac_1g_basex_us/test_taxi_eth_mac_1g_basex_us.sv @@ -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), diff --git a/src/eth/tb/taxi_eth_mac_phy_1g_basex/Makefile b/src/eth/tb/taxi_eth_mac_phy_1g_basex/Makefile index 20419cb..b845e3c 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex/Makefile @@ -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) diff --git a/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.py b/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.py index 2979fb0..eaf4969 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.py +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.py @@ -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 diff --git a/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.sv b/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.sv index 3ce135d..f8643d3 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.sv +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex/test_taxi_eth_mac_phy_1g_basex.sv @@ -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), diff --git a/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/Makefile b/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/Makefile index 013ea00..5b79b30 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/Makefile @@ -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) diff --git a/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.py b/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.py index db8f253..e20195e 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.py +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.py @@ -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'] diff --git a/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.sv b/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.sv index a9f224a..f93439c 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.sv +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex_fifo/test_taxi_eth_mac_phy_1g_basex_fifo.sv @@ -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), diff --git a/src/eth/tb/taxi_eth_phy_1g_basex/Makefile b/src/eth/tb/taxi_eth_phy_1g_basex/Makefile index 3f3bb18..826082f 100644 --- a/src/eth/tb/taxi_eth_phy_1g_basex/Makefile +++ b/src/eth/tb/taxi_eth_phy_1g_basex/Makefile @@ -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) diff --git a/src/eth/tb/taxi_eth_phy_1g_basex/test_taxi_eth_phy_1g_basex.py b/src/eth/tb/taxi_eth_phy_1g_basex/test_taxi_eth_phy_1g_basex.py index fbfc76e..a38ec4e 100644 --- a/src/eth/tb/taxi_eth_phy_1g_basex/test_taxi_eth_phy_1g_basex.py +++ b/src/eth/tb/taxi_eth_phy_1g_basex/test_taxi_eth_phy_1g_basex.py @@ -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']