eth: Add support for 1000BASE-X autonegotiation to 1000BASE-X MAC+PCS

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-06-30 00:32:05 -07:00
parent be7f5b5d27
commit 5f9e16d56c
16 changed files with 536 additions and 20 deletions

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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
*/

View File

@@ -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)

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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)

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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)

View File

@@ -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']

View File

@@ -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
*/