eth: Add support for USXGMII symbol replication to 32-bit AXIS/BASE-R encode module

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-07-08 01:39:20 -07:00
parent d667623b67
commit 473db729bf
7 changed files with 134 additions and 22 deletions

View File

@@ -21,6 +21,7 @@ module taxi_axis_baser_tx_32 #
parameter HDR_W = 2,
parameter logic GBX_IF_EN = 1'b0,
parameter GBX_CNT = 1,
parameter logic USXGMII_EN = 1'b0,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter PTP_TS_W = 96,
@@ -66,6 +67,9 @@ module taxi_axis_baser_tx_32 #
input wire logic [15:0] cfg_tx_max_pkt_len = 16'd1518-1,
input wire logic [7:0] cfg_tx_ifg = 8'd12,
input wire logic cfg_tx_enable,
input wire logic cfg_tx_usxgmii_en = 1'b1,
input wire logic cfg_tx_usxgmii_5g = 1'b0,
input wire logic [2:0] cfg_tx_usxgmii_speed = 3'b011,
/*
* Status
@@ -201,6 +205,9 @@ logic frame_len_lim_check_reg = '0, frame_len_lim_check_next;
logic [7:0] ifg_cnt_reg = '0, ifg_cnt_next;
logic [1:0] deficit_idle_cnt_reg = 2'd0, deficit_idle_cnt_next;
logic [9:0] rep_cnt_reg = '0;
logic rep_stall_reg = 1'b0;
logic s_axis_tx_tready_reg = 1'b0, s_axis_tx_tready_next;
logic [PTP_TS_W-1:0] m_axis_tx_cpl_ts_reg = '0, m_axis_tx_cpl_ts_next;
@@ -220,6 +227,7 @@ logic [DATA_W-1:0] output_data_reg = '0, output_data_next;
logic [DATA_W-1:0] output_data_d1_reg = '0;
out_type_t output_type_reg = OUTPUT_TYPE_IDLE, output_type_next;
logic start_packet_int_reg = 1'b0, start_packet_int_next;
logic start_packet_reg = 1'b0, start_packet_next;
logic [2:0] stat_tx_byte_reg = '0, stat_tx_byte_next;
@@ -234,7 +242,7 @@ logic stat_tx_err_oversize_reg = 1'b0, stat_tx_err_oversize_next;
logic stat_tx_err_user_reg = 1'b0, stat_tx_err_user_next;
logic stat_tx_err_underflow_reg = 1'b0, stat_tx_err_underflow_next;
assign s_axis_tx.tready = s_axis_tx_tready_reg && (!GBX_IF_EN || !tx_gbx_req_stall);
assign s_axis_tx.tready = s_axis_tx_tready_reg && (!GBX_IF_EN || !tx_gbx_req_stall) && (!USXGMII_EN || !rep_stall_reg);
assign encoded_tx_data = encoded_tx_data_reg;
assign encoded_tx_data_valid = GBX_IF_EN ? encoded_tx_data_valid_reg : 1'b1;
@@ -375,9 +383,10 @@ always_comb begin
end
end
output_data_next = s_tdata_reg;
output_type_next = OUTPUT_TYPE_IDLE;
output_data_next = output_data_reg;
output_type_next = output_type_reg;
start_packet_int_next = start_packet_int_reg;
start_packet_next = 1'b0;
stat_tx_byte_next = '0;
@@ -400,6 +409,32 @@ always_comb begin
// gearbox stall - hold state
state_next = state_reg;
s_axis_tx_tready_next = s_axis_tx_tready_reg;
output_data_next = output_data_reg;
output_type_next = output_type_reg;
end else if (USXGMII_EN && rep_stall_reg) begin
// USXGMII stall - replicate XGMII symbol
state_next = state_reg;
s_axis_tx_tready_next = s_axis_tx_tready_reg;
output_data_next = output_data_reg;
output_type_next = output_type_reg;
// SOP/EOP are not replicated
case (output_type_reg)
OUTPUT_TYPE_START: begin
// replace start character with 0xAA in replications
output_data_next[7:0] = 8'hAA;
output_type_next = OUTPUT_TYPE_DATA;
end
OUTPUT_TYPE_TERM_0, OUTPUT_TYPE_TERM_1, OUTPUT_TYPE_TERM_2, OUTPUT_TYPE_TERM_3: begin
// EOP is sent once followed by idles
output_type_next = OUTPUT_TYPE_IDLE;
end
default: begin
output_type_next = output_type_reg;
end
endcase
end else begin
// counter to measure frame length
if (&frame_len_reg[15:2] == 0) begin
@@ -495,7 +530,7 @@ always_comb begin
output_type_next = OUTPUT_TYPE_DATA;
s_axis_tx_tready_next = 1'b1;
start_packet_next = 1'b1;
start_packet_int_next = 1'b1;
state_next = STATE_PAYLOAD;
end
STATE_PAYLOAD: begin
@@ -509,6 +544,8 @@ always_comb begin
s_empty_next = keep2empty(s_axis_tx.tkeep);
stat_tx_byte_next = 3'(KEEP_W);
start_packet_next = start_packet_int_reg;
start_packet_int_next = 1'b0;
if (s_axis_tx.tvalid && s_axis_tx.tlast) begin
if (frame_len_lim_check_reg) begin
@@ -691,6 +728,7 @@ always_ff @(posedge clk) begin
tx_os_ready_reg <= 1'b0;
start_packet_int_reg <= start_packet_int_next;
start_packet_reg <= start_packet_next;
stat_tx_byte_reg <= stat_tx_byte_next;
@@ -829,7 +867,42 @@ always_ff @(posedge clk) begin
phase_reg <= 1'b1;
end
crc_state_reg <= crc_state;
if (!USXGMII_EN || !rep_stall_reg) begin
crc_state_reg <= crc_state;
end
if (USXGMII_EN && cfg_tx_usxgmii_en) begin
if (rep_cnt_reg == 0) begin
if (cfg_tx_usxgmii_5g) begin
case (cfg_tx_usxgmii_speed)
3'b000: rep_cnt_reg <= 499; // 10 Mbps
3'b001: rep_cnt_reg <= 49; // 100 Mbps
3'b010: rep_cnt_reg <= 4; // 1 Gbps
3'b100: rep_cnt_reg <= 1; // 2.5 Gbps
3'b101: rep_cnt_reg <= 0; // 5 Gbps
default: rep_cnt_reg <= 0;
endcase
end else begin
case (cfg_tx_usxgmii_speed)
3'b000: rep_cnt_reg <= 999; // 10 Mbps
3'b001: rep_cnt_reg <= 99; // 100 Mbps
3'b010: rep_cnt_reg <= 9; // 1 Gbps
3'b011: rep_cnt_reg <= 0; // 10 Gbps
3'b100: rep_cnt_reg <= 3; // 2.5 Gbps
3'b101: rep_cnt_reg <= 1; // 5 Gbps
default: rep_cnt_reg <= 0;
endcase
end
rep_stall_reg <= 1'b0;
end else begin
rep_cnt_reg <= rep_cnt_reg-1;
rep_stall_reg <= 1'b1;
end
end else begin
rep_cnt_reg <= '0;
rep_stall_reg <= 1'b0;
end
end
tx_gbx_sync_reg <= tx_gbx_req_sync;
@@ -840,6 +913,9 @@ always_ff @(posedge clk) begin
frame_reg <= 1'b0;
deficit_idle_cnt_reg <= 2'd0;
rep_cnt_reg <= '0;
rep_stall_reg <= 1'b0;
s_axis_tx_tready_reg <= 1'b0;
m_axis_tx_cpl_valid_reg <= 1'b0;

View File

@@ -38,6 +38,7 @@ export PARAM_DATA_W := 32
export PARAM_HDR_W := 2
export PARAM_GBX_IF_EN := 1
export PARAM_GBX_CNT := 1
export PARAM_USXGMII_EN := 1
export PARAM_DIC_EN := 1
export PARAM_PTP_TS_EN := 1
export PARAM_PTP_TS_FMT_TOD := 1

View File

@@ -38,7 +38,7 @@ except ImportError:
class TB:
def __init__(self, dut, gbx_cfg=None):
def __init__(self, dut, gbx_cfg=None, usxgmii_speed=None):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
@@ -75,6 +75,29 @@ class TB:
dut.cfg_tx_max_pkt_len.setimmediatevalue(0)
dut.cfg_tx_ifg.setimmediatevalue(0)
dut.cfg_tx_enable.setimmediatevalue(0)
if usxgmii_speed is not None:
dut.cfg_tx_usxgmii_en.setimmediatevalue(1)
dut.cfg_tx_usxgmii_5g.setimmediatevalue(0)
dut.cfg_tx_usxgmii_speed.setimmediatevalue(usxgmii_speed)
if usxgmii_speed == 0:
self.sink.set_xgmii_rep_count(999) # 10 Mbps
elif usxgmii_speed == 1:
self.sink.set_xgmii_rep_count(99) # 100 Mbps
elif usxgmii_speed == 2:
self.sink.set_xgmii_rep_count(9) # 1 Gbps
elif usxgmii_speed == 3:
self.sink.set_xgmii_rep_count(0) # 10 Gbps
elif usxgmii_speed == 4:
self.sink.set_xgmii_rep_count(3) # 2.5 Gbps
elif usxgmii_speed == 5:
self.sink.set_xgmii_rep_count(1) # 5 Gbps
else:
self.sink.set_xgmii_rep_count(0)
else:
dut.cfg_tx_usxgmii_en.setimmediatevalue(0)
dut.cfg_tx_usxgmii_5g.setimmediatevalue(0)
dut.cfg_tx_usxgmii_speed.setimmediatevalue(0b011)
self.sink.set_xgmii_rep_count(0)
self.stats = {}
self.stats["stat_tx_byte"] = 0
@@ -115,9 +138,9 @@ class TB:
self.stats[stat] += int(getattr(self.dut, stat).value)
async def run_test(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, ifg=12):
async def run_test(dut, gbx_cfg=None, usxgmii_speed=None, payload_lengths=None, payload_data=None, ifg=12):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, usxgmii_speed)
tb.dut.cfg_tx_max_pkt_len.value = 9218-1
tb.dut.cfg_tx_ifg.value = ifg
@@ -155,7 +178,7 @@ async def run_test(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, i
assert rx_frame.check_fcs()
assert rx_frame.ctrl is None
if gbx_cfg is None:
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*3) < 0.01
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*2) < 0.01
assert tb.sink.empty()
@@ -178,9 +201,9 @@ async def run_test(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, i
await RisingEdge(dut.clk)
async def run_test_underrun(dut, gbx_cfg=None, ifg=12):
async def run_test_underrun(dut, gbx_cfg=None, usxgmii_speed=None, ifg=12):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, usxgmii_speed)
tb.dut.cfg_tx_max_pkt_len.value = 9218-1
tb.dut.cfg_tx_ifg.value = ifg
@@ -198,12 +221,12 @@ async def run_test_underrun(dut, gbx_cfg=None, ifg=12):
test_frame = AxiStreamFrame(test_data)
await tb.source.send(test_frame)
for k in range(32):
for k in range(32*(tb.sink.get_xgmii_rep_count()+1)):
await RisingEdge(dut.clk)
tb.source.pause = True
for k in range(4):
for k in range(4*(tb.sink.get_xgmii_rep_count()+1)):
await RisingEdge(dut.clk)
tb.source.pause = False
@@ -240,9 +263,9 @@ async def run_test_underrun(dut, gbx_cfg=None, ifg=12):
await RisingEdge(dut.clk)
async def run_test_error(dut, gbx_cfg=None, ifg=12):
async def run_test_error(dut, gbx_cfg=None, usxgmii_speed=None, ifg=12):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, usxgmii_speed)
tb.dut.cfg_tx_max_pkt_len.value = 9218-1
tb.dut.cfg_tx_ifg.value = ifg
@@ -294,9 +317,9 @@ async def run_test_error(dut, gbx_cfg=None, ifg=12):
await RisingEdge(dut.clk)
async def run_test_oversize(dut, gbx_cfg=None, ifg=12):
async def run_test_oversize(dut, gbx_cfg=None, usxgmii_speed=None, ifg=12):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, usxgmii_speed)
tb.dut.cfg_tx_max_pkt_len.value = 1518-1
tb.dut.cfg_tx_ifg.value = ifg
@@ -383,9 +406,9 @@ async def run_test_oversize(dut, gbx_cfg=None, ifg=12):
await RisingEdge(dut.clk)
async def run_test_os(dut, gbx_cfg=None):
async def run_test_os(dut, gbx_cfg=None, usxgmii_speed=None):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, usxgmii_speed)
await tb.reset()
@@ -435,6 +458,7 @@ if getattr(cocotb, 'top', None) is not None:
factory.add_option("payload_lengths", [size_list])
factory.add_option("payload_data", [incrementing_payload])
factory.add_option("ifg", [12])
factory.add_option("usxgmii_speed", [None, 2, 4, 5, 3])
factory.add_option("gbx_cfg", gbx_cfgs)
factory.generate_tests()
@@ -446,10 +470,12 @@ if getattr(cocotb, 'top', None) is not None:
factory = TestFactory(test)
factory.add_option("ifg", [12])
factory.add_option("usxgmii_speed", [None, 2, 4, 5, 3])
factory.add_option("gbx_cfg", gbx_cfgs)
factory.generate_tests()
factory = TestFactory(run_test_os)
factory.add_option("usxgmii_speed", [None, 2, 4, 5, 3])
factory.add_option("gbx_cfg", gbx_cfgs)
factory.generate_tests()
@@ -497,6 +523,7 @@ def test_taxi_axis_baser_tx_32(request, gbx_en, dic_en):
parameters['HDR_W'] = 2
parameters['GBX_IF_EN'] = gbx_en
parameters['GBX_CNT'] = 1
parameters['USXGMII_EN'] = 1
parameters['DIC_EN'] = dic_en
parameters['PTP_TS_EN'] = 1
parameters['PTP_TS_FMT_TOD'] = 1

View File

@@ -22,6 +22,7 @@ module test_taxi_axis_baser_tx_32 #
parameter HDR_W = 2,
parameter logic GBX_IF_EN = 1'b0,
parameter GBX_CNT = 1,
parameter logic USXGMII_EN = 1'b1,
parameter logic DIC_EN = 1'b1,
parameter logic PTP_TS_EN = 1'b0,
parameter logic PTP_TS_FMT_TOD = 1'b1,
@@ -58,6 +59,9 @@ logic [PTP_TS_W-1:0] ptp_ts;
logic [15:0] cfg_tx_max_pkt_len;
logic [7:0] cfg_tx_ifg;
logic cfg_tx_enable;
logic cfg_tx_usxgmii_en;
logic cfg_tx_usxgmii_5g;
logic [2:0] cfg_tx_usxgmii_speed;
logic tx_start_packet;
logic [2:0] stat_tx_byte;
@@ -77,6 +81,7 @@ taxi_axis_baser_tx_32 #(
.HDR_W(HDR_W),
.GBX_IF_EN(GBX_IF_EN),
.GBX_CNT(GBX_CNT),
.USXGMII_EN(USXGMII_EN),
.DIC_EN(DIC_EN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_W(PTP_TS_W),
@@ -122,6 +127,9 @@ uut (
.cfg_tx_max_pkt_len(cfg_tx_max_pkt_len),
.cfg_tx_ifg(cfg_tx_ifg),
.cfg_tx_enable(cfg_tx_enable),
.cfg_tx_usxgmii_en(cfg_tx_usxgmii_en),
.cfg_tx_usxgmii_5g(cfg_tx_usxgmii_5g),
.cfg_tx_usxgmii_speed(cfg_tx_usxgmii_speed),
/*
* Status

View File

@@ -308,7 +308,7 @@ async def run_test_tx(dut, port=0, payload_lengths=None, payload_data=None, ifg=
pipe_delay = 6
else:
if dut.COMBINED_MAC_PCS.value:
pipe_delay = 7
pipe_delay = 6
else:
pipe_delay = 8

View File

@@ -246,7 +246,7 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
if len(dut.serdes_tx_data) == 64:
pipe_delay = 5
else:
pipe_delay = 6
pipe_delay = 5
tb = TB(dut, gbx_cfg)

View File

@@ -210,7 +210,7 @@ async def run_test_tx(dut, gbx_cfg=None, payload_lengths=None, payload_data=None
if len(dut.serdes_tx_data) == 64:
pipe_delay = 5
else:
pipe_delay = 6
pipe_delay = 5
tb = TB(dut, gbx_cfg)