diff --git a/src/eth/rtl/taxi_eth_mac_phy_1g_basex.f b/src/eth/rtl/taxi_eth_mac_phy_1g_basex.f index 11f0511..24e7e3b 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_1g_basex.f +++ b/src/eth/rtl/taxi_eth_mac_phy_1g_basex.f @@ -1,6 +1,7 @@ taxi_eth_mac_phy_1g_basex.sv taxi_eth_mac_phy_1g_basex_rx.f taxi_eth_mac_phy_1g_basex_tx.f +taxi_eth_phy_1g_basex_an.sv taxi_eth_mac_stats.f taxi_mac_ctrl_tx.sv taxi_mac_ctrl_rx.sv 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 a64fa71..28cc0ce 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_1g_basex.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_1g_basex.sv @@ -21,6 +21,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -76,6 +77,17 @@ module taxi_eth_mac_phy_1g_basex # input wire logic serdes_rx_data_valid = 1'b1, output wire logic serdes_rx_reset_req, + /* + * Autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + output wire logic an_intr, + output wire logic an_complete, + input wire logic [15:0] an_adv_ability = 16'h0020, + output wire logic [15:0] an_lp_adv_ability, + /* * PTP */ @@ -353,10 +365,97 @@ end else begin end +// Autonegotiation +wire logic [15:0] rx_an_cfg; +wire logic rx_an_cfg_valid; +wire logic rx_an_ability_match; +wire logic rx_an_ack_match; +wire logic rx_an_idle_match; + +wire logic [15:0] tx_an_cfg; +wire logic tx_an_cfg_valid; +wire logic tx_an_cfg_ready; + +if (AN_EN) begin : an + + // synchronize RX signals to TX + wire [15:0] sync_rx_an_cfg; + wire sync_rx_an_cfg_valid; + wire sync_rx_an_ability_match; + wire sync_rx_an_ack_match; + wire sync_rx_an_idle_match; + + taxi_sync_signal #( + .WIDTH(16+4), + .N(2) + ) + sync_inst ( + .clk(tx_clk), + + .in({ + rx_an_cfg, + rx_an_cfg_valid, + rx_an_ability_match, + rx_an_ack_match, + rx_an_idle_match + }), + .out({ + sync_rx_an_cfg, + sync_rx_an_cfg_valid, + sync_rx_an_ability_match, + sync_rx_an_ack_match, + sync_rx_an_idle_match + }) + ); + + taxi_eth_phy_1g_basex_an #( + .DATA_W(DATA_W) + ) + an_inst ( + .clk(tx_clk), + .rst(tx_rst), + + /* + * AN config register + */ + .rx_an_cfg(sync_rx_an_cfg), + .rx_an_cfg_valid(sync_rx_an_cfg_valid), + .rx_an_ability_match(sync_rx_an_ability_match), + .rx_an_ack_match(sync_rx_an_ack_match), + .rx_an_idle_match(sync_rx_an_idle_match), + + .tx_an_cfg(tx_an_cfg), + .tx_an_cfg_valid(tx_an_cfg_valid), + .tx_an_cfg_ready(tx_an_cfg_ready), + + /* + * Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_intr(an_intr), + .an_complete(an_complete), + .an_adv_ability(an_adv_ability), + .an_lp_adv_ability(an_lp_adv_ability) + ); + +end else begin : an + + assign tx_an_cfg = '0; + assign tx_an_cfg_valid = 1'b0; + + assign an_intr = 1'b0; + assign an_complete = 1'b0; + assign an_lp_adv_ability = '0; + +end + taxi_eth_mac_phy_1g_basex_rx #( .DATA_W(DATA_W), .CTRL_W(CTRL_W), .GBX_IF_EN(RX_GBX_IF_EN), + .AN_EN(AN_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), .PTP_TS_W(PTP_TS_W), @@ -382,6 +481,15 @@ rx_inst ( .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * AN config register + */ + .rx_an_cfg(rx_an_cfg), + .rx_an_cfg_valid(rx_an_cfg_valid), + .rx_an_ability_match(rx_an_ability_match), + .rx_an_ack_match(rx_an_ack_match), + .rx_an_idle_match(rx_an_idle_match), + /* * PTP */ @@ -423,6 +531,7 @@ taxi_eth_mac_phy_1g_basex_tx #( .DATA_W(DATA_W), .CTRL_W(CTRL_W), .GBX_IF_EN(TX_GBX_IF_EN), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), @@ -455,6 +564,13 @@ tx_inst ( .serdes_tx_gbx_req_stall(serdes_tx_gbx_req_stall), .serdes_tx_gbx_sync(serdes_tx_gbx_sync), + /* + * AN config register + */ + .tx_an_cfg(tx_an_cfg), + .tx_an_cfg_valid(tx_an_cfg_valid), + .tx_an_cfg_ready(tx_an_cfg_ready), + /* * PTP */ 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 0b135da..ebc6191 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,6 +21,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -89,6 +90,17 @@ module taxi_eth_mac_phy_1g_basex_fifo # input wire logic serdes_rx_data_valid = 1'b1, output wire logic serdes_rx_reset_req, + /* + * Autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + output wire logic an_intr, + output wire logic an_complete, + input wire logic [15:0] an_adv_ability = 16'h0020, + output wire logic [15:0] an_lp_adv_ability, + /* * PTP clock */ @@ -297,6 +309,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), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -350,6 +363,17 @@ mac_phy_inst ( .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_intr(an_intr), + .an_complete(an_complete), + .an_adv_ability(an_adv_ability), + .an_lp_adv_ability(an_lp_adv_ability), + /* * PTP */ diff --git a/src/eth/rtl/taxi_eth_mac_phy_1g_basex_rx.sv b/src/eth/rtl/taxi_eth_mac_phy_1g_basex_rx.sv index c322876..7723ecb 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_1g_basex_rx.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_1g_basex_rx.sv @@ -20,6 +20,7 @@ module taxi_eth_mac_phy_1g_basex_rx # parameter DATA_W = 16, parameter CTRL_W = (DATA_W/8), parameter logic GBX_IF_EN = 1'b0, + parameter logic AN_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, parameter PTP_TS_W = PTP_TS_FMT_TOD ? 96 : 64, @@ -45,6 +46,15 @@ module taxi_eth_mac_phy_1g_basex_rx # input wire logic serdes_rx_data_valid = 1'b1, output wire logic serdes_rx_reset_req, + /* + * AN config register + */ + output wire logic [15:0] rx_an_cfg, + output wire logic rx_an_cfg_valid, + output wire logic rx_an_ability_match, + output wire logic rx_an_ack_match, + output wire logic rx_an_idle_match, + /* * PTP */ @@ -136,7 +146,7 @@ if (DATA_W == 16) begin .DATA_W(DATA_W), .CTRL_W(CTRL_W), .GBX_IF_EN(GBX_IF_EN), - .AN_EN(1'b0), + .AN_EN(AN_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_FMT_TOD(PTP_TS_FMT_TOD), .PTP_TS_W(PTP_TS_W) @@ -160,11 +170,11 @@ if (DATA_W == 16) begin /* * AN config register */ - .rx_an_cfg(), - .rx_an_cfg_valid(), - .rx_an_ability_match(), - .rx_an_ack_match(), - .rx_an_idle_match(), + .rx_an_cfg(rx_an_cfg), + .rx_an_cfg_valid(rx_an_cfg_valid), + .rx_an_ability_match(rx_an_ability_match), + .rx_an_ack_match(rx_an_ack_match), + .rx_an_idle_match(rx_an_idle_match), /* * PTP @@ -204,7 +214,7 @@ end else begin .DATA_W(DATA_W), .CTRL_W(CTRL_W), .GBX_IF_EN(GBX_IF_EN), - .AN_EN(1'b0), + .AN_EN(AN_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_W(PTP_TS_W) ) @@ -227,11 +237,11 @@ end else begin /* * AN config register */ - .rx_an_cfg(), - .rx_an_cfg_valid(), - .rx_an_ability_match(), - .rx_an_ack_match(), - .rx_an_idle_match(), + .rx_an_cfg(rx_an_cfg), + .rx_an_cfg_valid(rx_an_cfg_valid), + .rx_an_ability_match(rx_an_ability_match), + .rx_an_ack_match(rx_an_ack_match), + .rx_an_idle_match(rx_an_idle_match), /* * PTP diff --git a/src/eth/rtl/taxi_eth_mac_phy_1g_basex_tx.sv b/src/eth/rtl/taxi_eth_mac_phy_1g_basex_tx.sv index d8db389..526e04f 100644 --- a/src/eth/rtl/taxi_eth_mac_phy_1g_basex_tx.sv +++ b/src/eth/rtl/taxi_eth_mac_phy_1g_basex_tx.sv @@ -20,6 +20,7 @@ module taxi_eth_mac_phy_1g_basex_tx # parameter DATA_W = 16, parameter CTRL_W = (DATA_W/8), parameter logic GBX_IF_EN = 1'b0, + parameter logic AN_EN = 1'b1, parameter logic DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TS_FMT_TOD = 1'b1, @@ -52,6 +53,13 @@ module taxi_eth_mac_phy_1g_basex_tx # input wire logic serdes_tx_gbx_req_stall = 1'b0, output wire logic serdes_tx_gbx_sync, + /* + * AN config register + */ + input wire logic [15:0] tx_an_cfg = '0, + input wire logic tx_an_cfg_valid = 1'b0, + output wire logic tx_an_cfg_ready, + /* * PTP */ @@ -142,7 +150,7 @@ if (DATA_W == 16) begin .CTRL_W(CTRL_W), .GBX_IF_EN(GBX_IF_EN), .GBX_CNT(1), - .AN_EN(1'b0), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_W(PTP_TS_W), @@ -173,9 +181,9 @@ if (DATA_W == 16) begin /* * AN config register */ - .tx_an_cfg('0), - .tx_an_cfg_valid(1'b0), - .tx_an_cfg_ready(), + .tx_an_cfg(tx_an_cfg), + .tx_an_cfg_valid(tx_an_cfg_valid), + .tx_an_cfg_ready(tx_an_cfg_ready), /* * PTP @@ -213,7 +221,7 @@ end else begin .CTRL_W(CTRL_W), .GBX_IF_EN(GBX_IF_EN), .GBX_CNT(1), - .AN_EN(1'b0), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TS_W(PTP_TS_W), @@ -244,9 +252,9 @@ end else begin /* * AN config register */ - .tx_an_cfg('0), - .tx_an_cfg_valid(1'b0), - .tx_an_cfg_ready(), + .tx_an_cfg(tx_an_cfg), + .tx_an_cfg_valid(tx_an_cfg_valid), + .tx_an_cfg_ready(tx_an_cfg_ready), /* * PTP 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 0e51030..c5dc148 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,6 +53,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -130,6 +131,17 @@ module taxi_eth_mac_1g_basex_us # */ taxi_axis_if.src m_axis_rx[CNT], + /* + * Autonegotiation + */ + input wire logic an_en[CNT] = '{CNT{1'b1}}, + input wire logic an_restart[CNT] = '{CNT{1'b0}}, + input wire logic an_speedup[CNT] = '{CNT{1'b0}}, + output wire logic an_intr[CNT], + output wire logic an_complete[CNT], + input wire logic [15:0] an_adv_ability[CNT] = '{CNT{16'h0020}}, + output wire logic [15:0] an_lp_adv_ability[CNT], + /* * PTP clock */ @@ -422,6 +434,7 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch // MAC/PHY parameters .COMBINED_MAC_PCS(COMBINED_MAC_PCS), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -513,6 +526,17 @@ for (genvar n = 0; n < CNT; n = n + 1) begin : ch */ .m_axis_rx(m_axis_rx[n]), + /* + * Autonegotiation + */ + .an_en(an_en[n]), + .an_restart(an_restart[n]), + .an_speedup(an_speedup[n]), + .an_intr(an_intr[n]), + .an_complete(an_complete[n]), + .an_adv_ability(an_adv_ability[n]), + .an_lp_adv_ability(an_lp_adv_ability[n]), + /* * PTP clock */ 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 21d3cd1..ae3c758 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,6 +52,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -143,6 +144,17 @@ module taxi_eth_mac_1g_basex_us_ch # */ taxi_axis_if.src m_axis_rx, + /* + * Autonegotiation + */ + input wire logic an_en = 1'b1, + input wire logic an_restart = 1'b0, + input wire logic an_speedup = 1'b0, + output wire logic an_intr, + output wire logic an_complete, + input wire logic [15:0] an_adv_ability = 16'h0020, + output wire logic [15:0] an_lp_adv_ability, + /* * PTP clock */ @@ -555,6 +567,7 @@ if (COMBINED_MAC_PCS) begin : mac .CTRL_W(CTRL_W), .TX_GBX_IF_EN(GBX_EN), .RX_GBX_IF_EN(GBX_EN), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -608,6 +621,17 @@ if (COMBINED_MAC_PCS) begin : mac .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_reset_req(rx_reset_req), + /* + * Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_intr(an_intr), + .an_complete(an_complete), + .an_adv_ability(an_adv_ability), + .an_lp_adv_ability(an_lp_adv_ability), + /* * PTP */ 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 d27b6a5..089e068 100644 --- a/src/eth/tb/taxi_eth_mac_1g_basex_us/Makefile +++ b/src/eth/tb/taxi_eth_mac_1g_basex_us/Makefile @@ -43,6 +43,7 @@ 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_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 6b2eaef..595daea 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 @@ -127,6 +127,11 @@ class TB: dut.rx_rst_in.setimmediatevalue([0]*4) dut.tx_rst_in.setimmediatevalue([0]*4) + dut.an_en.setimmediatevalue([0]*4) + dut.an_restart.setimmediatevalue([0]*4) + dut.an_speedup.setimmediatevalue([1]*4) + dut.an_adv_ability.setimmediatevalue([0x0020]*4) + dut.stat_rx_fifo_drop.setimmediatevalue([0]*4) dut.cfg_tx_pad_en.setimmediatevalue([0]*4) @@ -774,6 +779,81 @@ async def run_test_pfc(dut, port=0, ifg=12): await RisingEdge(dut.xcvr_ctrl_clk) +async def run_test_an(dut, port=0): + + tb = TB(dut) + + tb.dut.an_en[port].value = 1 + tb.dut.an_restart[port].value = 0 + tb.dut.an_speedup[port].value = 1 + tb.dut.an_adv_ability[port].value = 0x0020 + + await tb.reset() + + tb.log.info("Wait for reset") + while int(dut.rx_rst_out[port].value): + await RisingEdge(dut.xcvr_ctrl_clk) + + tb.log.info("Wait for block lock") + while not int(dut.rx_block_lock[port].value): + await RisingEdge(dut.xcvr_ctrl_clk) + + for k in range(100): + await RisingEdge(dut.xcvr_ctrl_clk) + + tb.log.info("AN_RESTART") + tb.serdes_sources[port].set_an_cfg(0x0000) + + # link timer + for k in range(1250): + await RisingEdge(dut.tx_clk[port]) + + tb.log.info("ABILITY_DETECT") + tb.serdes_sources[port].set_an_cfg(0x002A) + + 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 + + assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability[port].value) & 0xbfff + + 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: + break + + tb.log.info("COMPLETE_ACKNOWLEDGE") + # link timer + for k in range(1250): + 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("IDLE_DETECT") + tb.serdes_sources[port].set_an_cfg(None) + + # link timer + for k in range(1250): + await RisingEdge(dut.tx_clk[port]) + + while True: + await RisingEdge(dut.tx_clk[port]) + if tb.serdes_sinks[port].get_an_idle_match(): + break + + for k in range(10): + await RisingEdge(dut.tx_clk[port]) + + def size_list(): return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -811,6 +891,11 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("ifg", [12]) factory.generate_tests() + if cocotb.top.AN_EN.value: + for test in [run_test_an]: + factory = TestFactory(test) + factory.generate_tests() + # cocotb-test 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 c2ce550..62caed5 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,6 +42,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -111,6 +112,14 @@ taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(TX_USER_W), .ID_EN(1), .ID_ taxi_axis_if #(.DATA_W(PTP_TS_W), .KEEP_W(1), .ID_EN(1), .ID_W(TX_TAG_W)) m_axis_tx_cpl[CNT](); taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(RX_USER_W)) m_axis_rx[CNT](); +logic an_en[CNT]; +logic an_restart[CNT]; +logic an_speedup[CNT]; +logic an_intr[CNT]; +logic an_complete[CNT]; +logic [15:0] an_adv_ability[CNT]; +logic [15:0] an_lp_adv_ability[CNT]; + logic ptp_clk; logic ptp_rst; logic ptp_sample_clk; @@ -263,6 +272,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), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -340,6 +350,17 @@ uut ( */ .m_axis_rx(m_axis_rx), + /* + * Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_intr(an_intr), + .an_complete(an_complete), + .an_adv_ability(an_adv_ability), + .an_lp_adv_ability(an_lp_adv_ability), + /* * PTP */ 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 ab3bbb8..20419cb 100644 --- a/src/eth/tb/taxi_eth_mac_phy_1g_basex/Makefile +++ b/src/eth/tb/taxi_eth_mac_phy_1g_basex/Makefile @@ -35,6 +35,7 @@ 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_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 4b8cccb..a20d04e 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 @@ -105,6 +105,11 @@ class TB: period_ns=self.ptp_clk_period ) + dut.an_en.setimmediatevalue(0) + dut.an_restart.setimmediatevalue(0) + dut.an_speedup.setimmediatevalue(1) + dut.an_adv_ability.setimmediatevalue(0x0020) + dut.stat_rx_fifo_drop.setimmediatevalue(0) dut.cfg_tx_pad_en.setimmediatevalue(0) @@ -703,6 +708,73 @@ 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): + + 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_adv_ability.value = 0x0020 + + 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) + + # link timer + for k in range(1250): + await RisingEdge(dut.tx_clk) + + tb.log.info("ABILITY_DETECT") + tb.serdes_source.set_an_cfg(0x002A) + + 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 + + assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff + + 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: + break + + tb.log.info("COMPLETE_ACKNOWLEDGE") + # link timer + for k in range(1250): + 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("IDLE_DETECT") + tb.serdes_source.set_an_cfg(None) + + # link timer + for k in range(1250): + await RisingEdge(dut.tx_clk) + + while True: + await RisingEdge(dut.tx_clk) + if tb.serdes_sink.get_an_idle_match(): + break + + for k in range(10): + await RisingEdge(dut.tx_clk) + + def size_list(): return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -745,6 +817,12 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() + if cocotb.top.AN_EN.value: + for test in [run_test_an]: + factory = TestFactory(test) + factory.add_option("gbx_cfg", gbx_cfgs) + factory.generate_tests() + # cocotb-test @@ -788,6 +866,7 @@ 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['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 3fe3995..18b32b7 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,6 +22,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -73,6 +74,14 @@ logic [CTRL_W-1:0] serdes_rx_data_k; logic serdes_rx_data_valid; logic serdes_rx_reset_req; +logic an_en; +logic an_restart; +logic an_speedup; +logic an_intr; +logic an_complete; +logic [15:0] an_adv_ability; +logic [15:0] an_lp_adv_ability; + logic ptp_clk; logic ptp_rst; logic ptp_sample_clk; @@ -205,6 +214,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), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -260,6 +270,17 @@ uut ( .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_intr(an_intr), + .an_complete(an_complete), + .an_adv_ability(an_adv_ability), + .an_lp_adv_ability(an_lp_adv_ability), + /* * PTP */ 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 8a21eec..013ea00 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,6 +36,7 @@ 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_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 c35f239..1b03266 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 @@ -103,6 +103,11 @@ class TB: period_ns=self.ptp_clk_period ) + dut.an_en.setimmediatevalue(0) + dut.an_restart.setimmediatevalue(0) + dut.an_speedup.setimmediatevalue(1) + dut.an_adv_ability.setimmediatevalue(0x0020) + dut.cfg_tx_pad_en.setimmediatevalue(0) dut.cfg_tx_min_pkt_len.setimmediatevalue(0) dut.cfg_tx_max_pkt_len.setimmediatevalue(0) @@ -262,6 +267,73 @@ 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): + + 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_adv_ability.value = 0x0020 + + 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) + + # link timer + for k in range(1250): + await RisingEdge(dut.tx_clk) + + tb.log.info("ABILITY_DETECT") + tb.serdes_source.set_an_cfg(0x002A) + + 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 + + assert lp_cfg & 0xbfff == int(tb.dut.an_adv_ability.value) & 0xbfff + + 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: + break + + tb.log.info("COMPLETE_ACKNOWLEDGE") + # link timer + for k in range(1250): + 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("IDLE_DETECT") + tb.serdes_source.set_an_cfg(None) + + # link timer + for k in range(1250): + await RisingEdge(dut.tx_clk) + + while True: + await RisingEdge(dut.tx_clk) + if tb.serdes_sink.get_an_idle_match(): + break + + for k in range(10): + await RisingEdge(dut.tx_clk) + + def size_list(): return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -290,6 +362,12 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("gbx_cfg", gbx_cfgs) factory.generate_tests() + if cocotb.top.AN_EN.value: + for test in [run_test_an]: + factory = TestFactory(test) + factory.add_option("gbx_cfg", gbx_cfgs) + factory.generate_tests() + # cocotb-test @@ -333,6 +411,7 @@ 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['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 d93ac09..3a00353 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,6 +23,7 @@ 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 DIC_EN = 1'b1, parameter logic PTP_TS_EN = 1'b0, parameter logic PTP_TD_EN = PTP_TS_EN, @@ -87,6 +88,14 @@ logic [CTRL_W-1:0] serdes_rx_data_k; logic serdes_rx_data_valid; logic serdes_rx_reset_req; +logic an_en; +logic an_restart; +logic an_speedup; +logic an_intr; +logic an_complete; +logic [15:0] an_adv_ability; +logic [15:0] an_lp_adv_ability; + logic ptp_clk; logic ptp_rst; logic ptp_sample_clk; @@ -134,6 +143,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), + .AN_EN(AN_EN), .DIC_EN(DIC_EN), .PTP_TS_EN(PTP_TS_EN), .PTP_TD_EN(PTP_TD_EN), @@ -202,6 +212,17 @@ uut ( .serdes_rx_data_valid(serdes_rx_data_valid), .serdes_rx_reset_req(serdes_rx_reset_req), + /* + * Autonegotiation + */ + .an_en(an_en), + .an_restart(an_restart), + .an_speedup(an_speedup), + .an_intr(an_intr), + .an_complete(an_complete), + .an_adv_ability(an_adv_ability), + .an_lp_adv_ability(an_lp_adv_ability), + /* * PTP clock */