mirror of
https://github.com/fpganinja/taxi.git
synced 2026-08-14 11:21:33 -07:00
eth: Add support for 1000BASE-X autonegotiation to 1000BASE-X PHY
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
taxi_eth_phy_1g_basex.sv
|
||||
taxi_eth_phy_1g_basex_rx.f
|
||||
taxi_eth_phy_1g_basex_tx.f
|
||||
taxi_eth_phy_1g_basex_an.sv
|
||||
../lib/taxi/src/sync/rtl/taxi_sync_signal.sv
|
||||
|
||||
@@ -21,6 +21,7 @@ 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 BIT_REVERSE = 1'b0,
|
||||
parameter logic ENC_8B10B_EN = 1'b0,
|
||||
parameter logic DEC_8B10B_EN = ENC_8B10B_EN,
|
||||
@@ -66,6 +67,17 @@ module taxi_eth_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,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
@@ -83,10 +95,97 @@ module taxi_eth_phy_1g_basex #
|
||||
input wire logic cfg_rx_prbs31_enable = 1'b0
|
||||
);
|
||||
|
||||
// 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_phy_1g_basex_rx #(
|
||||
.DATA_W(DATA_W),
|
||||
.CTRL_W(CTRL_W),
|
||||
.GBX_IF_EN(RX_GBX_IF_EN),
|
||||
.AN_EN(AN_EN),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.DEC_8B10B_EN(DEC_8B10B_EN),
|
||||
.PRBS31_EN(PRBS31_EN),
|
||||
@@ -113,6 +212,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),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
@@ -133,6 +241,7 @@ taxi_eth_phy_1g_basex_tx #(
|
||||
.DATA_W(DATA_W),
|
||||
.CTRL_W(CTRL_W),
|
||||
.GBX_IF_EN(TX_GBX_IF_EN),
|
||||
.AN_EN(AN_EN),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.ENC_8B10B_EN(ENC_8B10B_EN),
|
||||
.PRBS31_EN(PRBS31_EN),
|
||||
@@ -165,6 +274,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),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
|
||||
256
src/eth/rtl/taxi_eth_phy_1g_basex_an.sv
Normal file
256
src/eth/rtl/taxi_eth_phy_1g_basex_an.sv
Normal file
@@ -0,0 +1,256 @@
|
||||
// SPDX-License-Identifier: CERN-OHL-S-2.0
|
||||
/*
|
||||
|
||||
Copyright (c) 2026 FPGA Ninja, LLC
|
||||
|
||||
Authors:
|
||||
- Alex Forencich
|
||||
|
||||
*/
|
||||
|
||||
`resetall
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* 1000BASE-X Ethernet PHY autonegotiation
|
||||
*/
|
||||
module taxi_eth_phy_1g_basex_an #
|
||||
(
|
||||
parameter DATA_W = 16
|
||||
)
|
||||
(
|
||||
input wire logic clk,
|
||||
input wire logic rst,
|
||||
|
||||
/*
|
||||
* AN config register
|
||||
*/
|
||||
input wire logic [15:0] rx_an_cfg,
|
||||
input wire logic rx_an_cfg_valid,
|
||||
input wire logic rx_an_ability_match,
|
||||
input wire logic rx_an_ack_match,
|
||||
input wire logic rx_an_idle_match,
|
||||
|
||||
output wire logic [15:0] tx_an_cfg,
|
||||
output wire logic tx_an_cfg_valid,
|
||||
input wire logic tx_an_cfg_ready,
|
||||
|
||||
/*
|
||||
* 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
|
||||
);
|
||||
|
||||
localparam logic [15:0] AN_ACK = 16'h4000;
|
||||
localparam logic [15:0] AN_NP = 16'h8000;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
STATE_START,
|
||||
STATE_AN_RESTART,
|
||||
STATE_ABILITY_DET,
|
||||
STATE_ACK_DET,
|
||||
STATE_ACK_CPL,
|
||||
STATE_IDLE_DET,
|
||||
STATE_DONE
|
||||
} state_t;
|
||||
|
||||
state_t state_reg = STATE_START, state_next;
|
||||
|
||||
logic [20:0] delay_count_reg = '0, delay_count_next;
|
||||
logic delay_run_reg = 1'b0, delay_run_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;
|
||||
|
||||
logic an_intr_reg = 1'b0, an_intr_next;
|
||||
logic an_complete_reg = 1'b0, an_complete_next;
|
||||
logic [15:0] an_lp_adv_ability_reg = '0, an_lp_adv_ability_next;
|
||||
|
||||
assign tx_an_cfg = tx_an_cfg_reg;
|
||||
assign tx_an_cfg_valid = tx_an_cfg_valid_reg;
|
||||
|
||||
assign an_intr = an_intr_reg;
|
||||
assign an_complete = an_complete_reg;
|
||||
assign an_lp_adv_ability = an_lp_adv_ability_reg;
|
||||
|
||||
always_comb begin
|
||||
state_next = STATE_START;
|
||||
|
||||
delay_count_next = delay_count_reg;
|
||||
delay_run_next = delay_run_reg;
|
||||
|
||||
tx_an_cfg_next = tx_an_cfg_reg;
|
||||
tx_an_cfg_valid_next = tx_an_cfg_valid_reg && !tx_an_cfg_ready;
|
||||
|
||||
an_intr_next = 1'b0;
|
||||
an_complete_next = an_complete_reg;
|
||||
an_lp_adv_ability_next = an_lp_adv_ability_reg;
|
||||
|
||||
if (delay_run_reg) begin
|
||||
if (delay_count_reg != 0) begin
|
||||
delay_count_next = delay_count_reg - 1;
|
||||
end else begin
|
||||
delay_run_next = 1'b0;
|
||||
end
|
||||
end else begin
|
||||
// 10 ms timer
|
||||
if (DATA_W == 16) begin
|
||||
delay_count_next = an_speedup ? 625 : 625000;
|
||||
end else begin
|
||||
delay_count_next = an_speedup ? 1250 : 1250000;
|
||||
end
|
||||
end
|
||||
|
||||
case (state_reg)
|
||||
STATE_START: begin
|
||||
// start
|
||||
an_complete_next = 1'b0;
|
||||
|
||||
tx_an_cfg_next = '0;
|
||||
|
||||
if (an_en) begin
|
||||
tx_an_cfg_valid_next = 1'b1;
|
||||
if (delay_run_reg) begin
|
||||
// restart link timer
|
||||
delay_run_next = 1'b0;
|
||||
state_next = STATE_START;
|
||||
end else begin
|
||||
// AN restart state
|
||||
delay_run_next = 1'b1;
|
||||
state_next = STATE_AN_RESTART;
|
||||
end
|
||||
end else begin
|
||||
// AN disabled
|
||||
state_next = STATE_START;
|
||||
end
|
||||
end
|
||||
STATE_AN_RESTART: begin
|
||||
// AN restart - send zeroed config reg to trigger link partner to restart the AN process
|
||||
tx_an_cfg_next = '0;
|
||||
tx_an_cfg_valid_next = 1'b1;
|
||||
|
||||
if (!delay_run_reg) begin
|
||||
// link timer expired
|
||||
state_next = STATE_ABILITY_DET;
|
||||
end else begin
|
||||
state_next = STATE_AN_RESTART;
|
||||
end
|
||||
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_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 begin
|
||||
state_next = STATE_ABILITY_DET;
|
||||
end
|
||||
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_valid_next = 1'b1;
|
||||
|
||||
if (rx_an_ability_match && rx_an_cfg == 0) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else if (rx_an_ack_match) begin
|
||||
// acknowledge match
|
||||
an_lp_adv_ability_next = rx_an_cfg;
|
||||
if (rx_an_cfg == (an_lp_adv_ability_reg | AN_ACK)) begin
|
||||
// consistent with previously-seen value
|
||||
delay_run_next = 1'b1;
|
||||
state_next = STATE_ACK_CPL;
|
||||
end else begin
|
||||
// inconsistent, restart AN
|
||||
state_next = STATE_START;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_ACK_DET;
|
||||
end
|
||||
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_valid_next = 1'b1;
|
||||
|
||||
if (rx_an_ability_match && rx_an_cfg == 0) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else if (!delay_run_reg) begin
|
||||
// link timer expired
|
||||
delay_run_next = 1'b1;
|
||||
state_next = STATE_IDLE_DET;
|
||||
end else begin
|
||||
state_next = STATE_ACK_CPL;
|
||||
end
|
||||
end
|
||||
STATE_IDLE_DET: begin
|
||||
if (rx_an_ability_match && rx_an_cfg == 0) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else if (rx_an_idle_match && !delay_run_reg) begin
|
||||
// idle match and link timer expired
|
||||
an_complete_next = 1'b1;
|
||||
state_next = STATE_DONE;
|
||||
end else begin
|
||||
state_next = STATE_IDLE_DET;
|
||||
end
|
||||
end
|
||||
STATE_DONE: begin
|
||||
if (rx_an_ability_match && rx_an_cfg == 0) begin
|
||||
// restart request from link partner
|
||||
state_next = STATE_START;
|
||||
end else begin
|
||||
state_next = STATE_DONE;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
state_next = STATE_START;
|
||||
end
|
||||
endcase
|
||||
|
||||
if (!an_en || an_restart) begin
|
||||
state_next = STATE_START;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
delay_count_reg <= delay_count_next;
|
||||
delay_run_reg <= delay_run_next;
|
||||
|
||||
tx_an_cfg_reg <= tx_an_cfg_next;
|
||||
tx_an_cfg_valid_reg <= tx_an_cfg_valid_next;
|
||||
|
||||
an_intr_reg <= an_intr_next;
|
||||
an_complete_reg <= an_complete_next;
|
||||
an_lp_adv_ability_reg <= an_lp_adv_ability_next;
|
||||
|
||||
if (rst) begin
|
||||
state_reg <= STATE_START;
|
||||
|
||||
delay_count_reg <= '0;
|
||||
delay_run_reg <= 1'b0;
|
||||
|
||||
tx_an_cfg_valid_reg <= 1'b0;
|
||||
|
||||
an_intr_reg <= 1'b0;
|
||||
an_complete_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
||||
@@ -20,6 +20,7 @@ module taxi_eth_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 BIT_REVERSE = 1'b0,
|
||||
parameter logic DEC_8B10B_EN = 1'b0,
|
||||
parameter logic PRBS31_EN = 1'b0,
|
||||
@@ -46,6 +47,15 @@ module taxi_eth_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,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
@@ -115,7 +125,7 @@ taxi_gmii_basex_dec #(
|
||||
.DATA_W(DATA_W),
|
||||
.CTRL_W(CTRL_W),
|
||||
.GBX_IF_EN(GBX_IF_EN),
|
||||
.AN_EN(1'b0)
|
||||
.AN_EN(AN_EN)
|
||||
)
|
||||
dec_inst (
|
||||
.clk(clk),
|
||||
@@ -139,11 +149,11 @@ dec_inst (
|
||||
/*
|
||||
* 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),
|
||||
|
||||
/*
|
||||
* Status
|
||||
|
||||
@@ -20,6 +20,7 @@ module taxi_eth_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 BIT_REVERSE = 1'b0,
|
||||
parameter logic ENC_8B10B_EN = 1'b0,
|
||||
parameter logic PRBS31_EN = 1'b0,
|
||||
@@ -52,6 +53,13 @@ module taxi_eth_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,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
@@ -71,7 +79,7 @@ taxi_gmii_basex_enc #(
|
||||
.CTRL_W(CTRL_W),
|
||||
.GBX_IF_EN(GBX_IF_EN),
|
||||
.GBX_CNT(1),
|
||||
.AN_EN(1'b0)
|
||||
.AN_EN(AN_EN)
|
||||
)
|
||||
enc_inst (
|
||||
.clk(clk),
|
||||
@@ -99,9 +107,9 @@ enc_inst (
|
||||
/*
|
||||
* 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)
|
||||
);
|
||||
|
||||
taxi_eth_phy_1g_basex_tx_if #(
|
||||
|
||||
@@ -35,6 +35,7 @@ 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_BIT_REVERSE := "1'b0"
|
||||
export PARAM_ENC_8B10B_EN := "1'b0"
|
||||
export PARAM_DEC_8B10B_EN := $(PARAM_ENC_8B10B_EN)
|
||||
|
||||
@@ -75,6 +75,11 @@ class TB:
|
||||
gbx_cfg=gbx_cfg
|
||||
)
|
||||
|
||||
dut.an_en.value = 0
|
||||
dut.an_restart.value = 0
|
||||
dut.an_speedup.value = 1
|
||||
dut.an_adv_ability.value = 0x0020
|
||||
|
||||
dut.cfg_tx_prbs31_enable.setimmediatevalue(0)
|
||||
dut.cfg_rx_prbs31_enable.setimmediatevalue(0)
|
||||
|
||||
@@ -154,6 +159,73 @@ 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):
|
||||
|
||||
tb = TB(dut)
|
||||
|
||||
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) & 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
|
||||
|
||||
@@ -176,6 +248,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
|
||||
|
||||
@@ -217,6 +294,7 @@ 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['BIT_REVERSE'] = "1'b0"
|
||||
parameters['ENC_8B10B_EN'] = "1'b0"
|
||||
parameters['DEC_8B10B_EN'] = parameters['ENC_8B10B_EN']
|
||||
|
||||
Reference in New Issue
Block a user