eth: Support ordered sets in AXI stream-XGMII encode/decode logic

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-06-19 21:05:59 -07:00
parent 6706b9b30b
commit 67078fd39e
13 changed files with 340 additions and 18 deletions

View File

@@ -39,6 +39,13 @@ module taxi_axis_xgmii_rx_32 #
*/
taxi_axis_if.src m_axis_rx,
/*
* Ordered sets
*/
output wire logic [23:0] rx_os = '0,
output wire logic rx_os_sig = 1'b0,
output wire logic rx_os_valid = 1'b0,
/*
* PTP
*/
@@ -148,6 +155,10 @@ logic m_axis_rx_tvalid_reg = 1'b0, m_axis_rx_tvalid_next;
logic m_axis_rx_tlast_reg = 1'b0, m_axis_rx_tlast_next;
logic m_axis_rx_tuser_reg = 1'b0, m_axis_rx_tuser_next;
logic [23:0] rx_os_reg = '0;
logic rx_os_sig_reg = 1'b0;
logic rx_os_valid_reg = 1'b0;
logic start_packet_reg = 1'b0, start_packet_next;
logic [2:0] stat_rx_byte_reg = '0, stat_rx_byte_next;
@@ -192,6 +203,10 @@ if (PTP_TS_EN) begin
assign m_axis_rx.tuser[1 +: PTP_TS_W] = ptp_ts_out_reg;
end
assign rx_os = rx_os_reg;
assign rx_os_sig = rx_os_sig_reg;
assign rx_os_valid = rx_os_valid_reg;
assign rx_start_packet = start_packet_reg;
assign stat_rx_byte = stat_rx_byte_reg;
@@ -520,6 +535,8 @@ always_ff @(posedge clk) begin
m_axis_rx_tlast_reg <= m_axis_rx_tlast_next;
m_axis_rx_tuser_reg <= m_axis_rx_tuser_next;
rx_os_valid_reg <= 1'b0;
ptp_ts_out_reg <= ptp_ts_out_next;
start_packet_reg <= start_packet_next;
@@ -567,6 +584,15 @@ always_ff @(posedge clk) begin
crc_state_reg <= 32'hffffffff;
end
// ordered sets
if (xgmii_rxc == 4'b0001 && (xgmii_rxd[7:0] == XGMII_SEQ_OS || xgmii_rxd[7:0] == XGMII_SIG_OS)) begin
rx_os_reg[7:0] <= xgmii_rxd[31:24];
rx_os_reg[15:8] <= xgmii_rxd[23:16];
rx_os_reg[23:16] <= xgmii_rxd[15:8];
rx_os_sig_reg <= xgmii_rxd[7:0] == XGMII_SIG_OS;
rx_os_valid_reg <= 1'b1;
end
term_lane_d0_reg <= term_lane_reg;
crc_valid_reg <= crc_valid;
@@ -584,6 +610,8 @@ always_ff @(posedge clk) begin
m_axis_rx_tvalid_reg <= 1'b0;
rx_os_valid_reg <= 1'b0;
start_packet_reg <= 1'b0;
stat_rx_byte_reg <= '0;

View File

@@ -40,6 +40,13 @@ module taxi_axis_xgmii_rx_64 #
*/
taxi_axis_if.src m_axis_rx,
/*
* Ordered sets
*/
output wire logic [23:0] rx_os = '0,
output wire logic rx_os_sig = 1'b0,
output wire logic rx_os_valid = 1'b0,
/*
* PTP
*/
@@ -153,6 +160,10 @@ logic m_axis_rx_tvalid_reg = 1'b0, m_axis_rx_tvalid_next;
logic m_axis_rx_tlast_reg = 1'b0, m_axis_rx_tlast_next;
logic m_axis_rx_tuser_reg = 1'b0, m_axis_rx_tuser_next;
logic [23:0] rx_os_reg = '0;
logic rx_os_sig_reg = 1'b0;
logic rx_os_valid_reg = 1'b0;
logic [1:0] start_packet_reg = 2'b00;
logic [3:0] stat_rx_byte_reg = '0, stat_rx_byte_next;
@@ -207,6 +218,10 @@ if (PTP_TS_EN) begin
assign m_axis_rx.tuser[1 +: PTP_TS_W] = ptp_ts_out_reg;
end
assign rx_os = rx_os_reg;
assign rx_os_sig = rx_os_sig_reg;
assign rx_os_valid = rx_os_valid_reg;
assign rx_start_packet = start_packet_reg;
assign stat_rx_byte = stat_rx_byte_reg;
@@ -517,6 +532,8 @@ always_ff @(posedge clk) begin
m_axis_rx_tlast_reg <= m_axis_rx_tlast_next;
m_axis_rx_tuser_reg <= m_axis_rx_tuser_next;
rx_os_valid_reg <= 1'b0;
ptp_ts_out_reg <= ptp_ts_out_next;
start_packet_reg <= 2'b00;
@@ -626,6 +643,21 @@ always_ff @(posedge clk) begin
end
end
// ordered sets
if (xgmii_rxc[7:4] == 4'b0001 && (xgmii_rxd[39:32] == XGMII_SEQ_OS || xgmii_rxd[39:32] == XGMII_SIG_OS)) begin
rx_os_reg[7:0] <= xgmii_rxd[63:56];
rx_os_reg[15:8] <= xgmii_rxd[55:48];
rx_os_reg[23:16] <= xgmii_rxd[47:40];
rx_os_sig_reg <= xgmii_rxd[39:32] == XGMII_SIG_OS;
rx_os_valid_reg <= 1'b1;
end else if (xgmii_rxc[3:0] == 4'b0001 && (xgmii_rxd[7:0] == XGMII_SEQ_OS || xgmii_rxd[7:0] == XGMII_SIG_OS)) begin
rx_os_reg[7:0] <= xgmii_rxd[31:24];
rx_os_reg[15:8] <= xgmii_rxd[23:16];
rx_os_reg[23:16] <= xgmii_rxd[15:8];
rx_os_sig_reg <= xgmii_rxd[7:0] == XGMII_SIG_OS;
rx_os_valid_reg <= 1'b1;
end
lanes_swapped_d1_reg <= lanes_swapped_reg;
term_lane_d0_reg <= term_lane_reg;
@@ -645,6 +677,8 @@ always_ff @(posedge clk) begin
m_axis_rx_tvalid_reg <= 1'b0;
rx_os_valid_reg <= 1'b0;
start_packet_reg <= 2'b00;
stat_rx_byte_reg <= '0;

View File

@@ -46,6 +46,14 @@ module taxi_axis_xgmii_tx_32 #
input wire logic tx_gbx_req_stall = '0,
output wire logic [GBX_CNT-1:0] tx_gbx_sync,
/*
* Ordered sets
*/
input wire logic [23:0] tx_os = '0,
input wire logic tx_os_sig = 1'b0,
input wire logic tx_os_valid = 1'b0,
output wire logic tx_os_ready,
/*
* PTP
*/
@@ -160,6 +168,8 @@ logic [PTP_TS_W-1:0] m_axis_tx_cpl_ts_reg = '0, m_axis_tx_cpl_ts_next;
logic [TX_TAG_W-1:0] m_axis_tx_cpl_tag_reg = '0, m_axis_tx_cpl_tag_next;
logic m_axis_tx_cpl_valid_reg = 1'b0, m_axis_tx_cpl_valid_next;
logic tx_os_ready_reg = 1'b0, tx_os_ready_next;
logic [DATA_W-1:0] xgmii_txd_reg = {CTRL_W{XGMII_IDLE}}, xgmii_txd_next;
logic [CTRL_W-1:0] xgmii_txc_reg = {CTRL_W{1'b1}}, xgmii_txc_next;
logic xgmii_tx_valid_reg = 1'b0;
@@ -195,6 +205,8 @@ assign m_axis_tx_cpl.tid = m_axis_tx_cpl_tag_reg;
assign m_axis_tx_cpl.tdest = '0;
assign m_axis_tx_cpl.tuser = '0;
assign tx_os_ready = tx_os_ready_reg;
assign tx_start_packet = start_packet_reg;
assign stat_tx_byte = stat_tx_byte_reg;
@@ -319,9 +331,21 @@ always_comb begin
end
end
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
tx_os_ready_next = 1'b0;
if (tx_os_valid) begin
// Ordered sets
xgmii_txd_next[7:0] = tx_os_sig ? XGMII_SIG_OS : XGMII_SEQ_OS;
xgmii_txd_next[15:8] = tx_os[23:16];
xgmii_txd_next[23:16] = tx_os[15:8];
xgmii_txd_next[31:24] = tx_os[7:0];
xgmii_txc_next = 4'b0001;
tx_os_ready_next = 1'b1;
end else begin
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
end
start_packet_next = 1'b0;
@@ -406,9 +430,7 @@ always_comb begin
{frame_len_lim_cyc_next, frame_len_lim_last_next} = cfg_tx_max_pkt_len;
frame_len_lim_check_next = 1'b0;
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
// XGMII idle or ordered set
s_tdata_next = s_axis_tx.tdata;
s_empty_next = keep2empty(s_axis_tx.tkeep);
@@ -582,9 +604,7 @@ always_comb begin
// send IFG
s_axis_tx_tready_next = frame_next; // drop frame
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
// XGMII idle or ordered set
if (DIC_EN) begin
if (ifg_cnt_next > 8'd3 || frame_reg) begin
@@ -638,6 +658,8 @@ always_ff @(posedge clk) begin
m_axis_tx_cpl_tag_reg <= m_axis_tx_cpl_tag_next;
m_axis_tx_cpl_valid_reg <= m_axis_tx_cpl_valid_next;
tx_os_ready_reg <= tx_os_ready_next;
if (GBX_IF_EN && tx_gbx_req_stall) begin
// gearbox stall
end else begin
@@ -674,6 +696,8 @@ always_ff @(posedge clk) begin
m_axis_tx_cpl_valid_reg <= 1'b0;
tx_os_ready_reg <= 1'b0;
xgmii_txd_reg <= {CTRL_W{XGMII_IDLE}};
xgmii_txc_reg <= {CTRL_W{1'b1}};
xgmii_tx_valid_reg <= 1'b0;

View File

@@ -47,6 +47,14 @@ module taxi_axis_xgmii_tx_64 #
input wire logic tx_gbx_req_stall = '0,
output wire logic [GBX_CNT-1:0] tx_gbx_sync,
/*
* Ordered sets
*/
input wire logic [23:0] tx_os = '0,
input wire logic tx_os_sig = 1'b0,
input wire logic tx_os_valid = 1'b0,
output wire logic tx_os_ready,
/*
* PTP
*/
@@ -167,6 +175,8 @@ logic m_axis_tx_cpl_valid_reg = 1'b0;
logic m_axis_tx_cpl_valid_int_reg = 1'b0;
logic m_axis_tx_cpl_ts_borrow_reg = 1'b0;
logic tx_os_ready_reg = 1'b0, tx_os_ready_next;
logic [4+16-1:0] last_ts_reg = '0;
logic [4+16-1:0] ts_inc_reg = '0;
@@ -205,6 +215,8 @@ assign m_axis_tx_cpl.tid = m_axis_tx_cpl_tag_reg;
assign m_axis_tx_cpl.tdest = '0;
assign m_axis_tx_cpl.tuser = '0;
assign tx_os_ready = tx_os_ready_reg;
assign tx_start_packet = start_packet_reg;
assign stat_tx_byte = stat_tx_byte_reg;
@@ -355,9 +367,25 @@ always_comb begin
m_axis_tx_cpl_tag_next = m_axis_tx_cpl_tag_reg;
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
tx_os_ready_next = 1'b0;
if (tx_os_valid) begin
// Ordered sets
xgmii_txd_next[7:0] = tx_os_sig ? XGMII_SIG_OS : XGMII_SEQ_OS;
xgmii_txd_next[15:8] = tx_os[23:16];
xgmii_txd_next[23:16] = tx_os[15:8];
xgmii_txd_next[31:24] = tx_os[7:0];
xgmii_txd_next[39:32] = tx_os_sig ? XGMII_SIG_OS : XGMII_SEQ_OS;
xgmii_txd_next[47:40] = tx_os[23:16];
xgmii_txd_next[55:48] = tx_os[15:8];
xgmii_txd_next[63:56] = tx_os[7:0];
xgmii_txc_next = 8'b00010001;
tx_os_ready_next = 1'b1;
end else begin
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
end
stat_tx_byte_next = '0;
stat_tx_pkt_len_next = '0;
@@ -450,9 +478,7 @@ always_comb begin
frame_len_lim_check_next = 1'b0;
s_axis_tx_tready_next = cfg_tx_enable;
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
// XGMII idle or ordered set
s_tdata_next = s_axis_tx.tdata;
s_empty_next = keep2empty(s_axis_tx.tkeep);
@@ -615,9 +641,7 @@ always_comb begin
// send IFG
s_axis_tx_tready_next = frame_next; // drop frame
// XGMII idle
xgmii_txd_next = {CTRL_W{XGMII_IDLE}};
xgmii_txc_next = {CTRL_W{1'b1}};
// XGMII idle or ordered set
crc_data_next = {24'd0, s_axis_tx.tdata} ^ {56'd0, 32'hffffffff};
@@ -685,6 +709,8 @@ always_ff @(posedge clk) begin
m_axis_tx_cpl_valid_reg <= 1'b0;
m_axis_tx_cpl_valid_int_reg <= 1'b0;
tx_os_ready_reg <= tx_os_ready_next;
start_packet_reg <= 2'b00;
stat_tx_byte_reg <= stat_tx_byte_next;
@@ -778,6 +804,8 @@ always_ff @(posedge clk) begin
m_axis_tx_cpl_valid_reg <= 1'b0;
m_axis_tx_cpl_valid_int_reg <= 1'b0;
tx_os_ready_reg <= 1'b0;
xgmii_txd_reg <= {CTRL_W{XGMII_IDLE}};
xgmii_txc_reg <= {CTRL_W{1'b1}};
xgmii_tx_valid_reg <= 1'b0;

View File

@@ -408,6 +408,13 @@ if (DATA_W == 64) begin
*/
.m_axis_rx(axis_rx_int),
/*
* Ordered sets
*/
.rx_os(),
.rx_os_sig(),
.rx_os_valid(),
/*
* PTP
*/
@@ -471,6 +478,14 @@ if (DATA_W == 64) begin
.tx_gbx_req_stall(tx_gbx_req_stall),
.tx_gbx_sync(tx_gbx_sync),
/*
* Ordered sets
*/
.tx_os('0),
.tx_os_sig(1'b0),
.tx_os_valid(1'b0),
.tx_os_ready(),
/*
* PTP
*/
@@ -525,6 +540,13 @@ end else if (DATA_W == 32) begin
*/
.m_axis_rx(axis_rx_int),
/*
* Ordered sets
*/
.rx_os(),
.rx_os_sig(),
.rx_os_valid(),
/*
* PTP
*/
@@ -590,6 +612,14 @@ end else if (DATA_W == 32) begin
.tx_gbx_req_stall(tx_gbx_req_stall),
.tx_gbx_sync(tx_gbx_sync),
/*
* Ordered sets
*/
.tx_os('0),
.tx_os_sig(1'b0),
.tx_os_valid(1'b0),
.tx_os_ready(),
/*
* PTP
*/

View File

@@ -244,6 +244,33 @@ async def run_test_oversize(dut, ifg=12):
await RisingEdge(dut.clk)
async def run_test_os(dut):
tb = TB(dut)
await tb.reset()
for sig in [False, True]:
for k in range(24):
os = 1 << k
tb.source.set_os(os, sig)
for k in range(20):
await RisingEdge(dut.clk)
assert int(dut.rx_os.value) == os
assert int(dut.rx_os_sig.value) == sig
tb.source.set_os(None)
for k in range(20):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
def size_list():
return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 + [i for i in range(64, 73) for k in range(8)]
@@ -268,6 +295,9 @@ if getattr(cocotb, 'top', None) is not None:
factory.add_option("ifg", list(range(0, 13)))
factory.generate_tests()
factory = TestFactory(run_test_os)
factory.generate_tests()
# cocotb-test

View File

@@ -38,6 +38,10 @@ logic xgmii_rx_valid;
taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(USER_W)) m_axis_rx();
logic [23:0] rx_os;
logic rx_os_sig;
logic rx_os_valid;
logic [PTP_TS_W-1:0] ptp_ts;
logic [15:0] cfg_rx_max_pkt_len;
@@ -83,6 +87,13 @@ uut (
*/
.m_axis_rx(m_axis_rx),
/*
* Ordered sets
*/
.rx_os(rx_os),
.rx_os_sig(rx_os_sig),
.rx_os_valid(rx_os_valid),
/*
* PTP
*/

View File

@@ -241,6 +241,33 @@ async def run_test_oversize(dut, ifg=12):
await RisingEdge(dut.clk)
async def run_test_os(dut):
tb = TB(dut)
await tb.reset()
for sig in [False, True]:
for k in range(24):
os = 1 << k
tb.source.set_os(os, sig)
for k in range(20):
await RisingEdge(dut.clk)
assert int(dut.rx_os.value) == os
assert int(dut.rx_os_sig.value) == sig
tb.source.set_os(None)
for k in range(20):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
def size_list():
return list(range(60, 128)) + [512, 1514, 9214] + [60]*10 + [i for i in range(64, 73) for k in range(8)]
@@ -265,6 +292,9 @@ if getattr(cocotb, 'top', None) is not None:
factory.add_option("ifg", list(range(0, 13)))
factory.generate_tests()
factory = TestFactory(run_test_os)
factory.generate_tests()
# cocotb-test

View File

@@ -39,6 +39,10 @@ logic xgmii_rx_valid;
taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(USER_W)) m_axis_rx();
logic [23:0] rx_os;
logic rx_os_sig;
logic rx_os_valid;
logic [PTP_TS_W-1:0] ptp_ts;
logic [15:0] cfg_rx_max_pkt_len;
@@ -85,6 +89,13 @@ uut (
*/
.m_axis_rx(m_axis_rx),
/*
* Ordered sets
*/
.rx_os(rx_os),
.rx_os_sig(rx_os_sig),
.rx_os_valid(rx_os_valid),
/*
* PTP
*/

View File

@@ -41,6 +41,10 @@ class TB:
self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.clk)
self.tx_cpl_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_tx_cpl), dut.clk, dut.rst)
dut.tx_os.setimmediatevalue(0)
dut.tx_os_sig.setimmediatevalue(0)
dut.tx_os_valid.setimmediatevalue(0)
dut.cfg_tx_max_pkt_len.setimmediatevalue(0)
dut.cfg_tx_ifg.setimmediatevalue(0)
dut.cfg_tx_enable.setimmediatevalue(0)
@@ -445,6 +449,34 @@ async def run_test_oversize(dut, ifg=12):
await RisingEdge(dut.clk)
async def run_test_os(dut):
tb = TB(dut)
await tb.reset()
for sig in [False, True]:
for k in range(24):
os = 1 << k
dut.tx_os.value = os
dut.tx_os_sig.value = sig
dut.tx_os_valid.value = 1
for k in range(20):
await RisingEdge(dut.clk)
assert tb.sink.get_os() == (os, sig)
dut.tx_os_valid.value = 0
for k in range(20):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
def size_list():
return list(range(16, 128)) + [512, 1514, 9214] + [60]*10 + [i for i in range(64, 73) for k in range(8)]
@@ -480,6 +512,9 @@ if getattr(cocotb, 'top', None) is not None:
factory.add_option("ifg", [12])
factory.generate_tests()
factory = TestFactory(run_test_os)
factory.generate_tests()
# cocotb-test

View File

@@ -46,6 +46,11 @@ logic [GBX_CNT-1:0] tx_gbx_req_sync;
logic tx_gbx_req_stall;
logic [GBX_CNT-1:0] tx_gbx_sync;
logic [23:0] tx_os;
logic tx_os_sig;
logic tx_os_valid;
logic tx_os_ready;
logic [PTP_TS_W-1:0] ptp_ts;
logic [15:0] cfg_tx_max_pkt_len;
@@ -95,6 +100,14 @@ uut (
.tx_gbx_req_stall(tx_gbx_req_stall),
.tx_gbx_sync(tx_gbx_sync),
/*
* Ordered sets
*/
.tx_os(tx_os),
.tx_os_sig(tx_os_sig),
.tx_os_valid(tx_os_valid),
.tx_os_ready(tx_os_ready),
/*
* PTP
*/

View File

@@ -41,6 +41,10 @@ class TB:
self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.clk)
self.tx_cpl_sink = AxiStreamSink(AxiStreamBus.from_entity(dut.m_axis_tx_cpl), dut.clk, dut.rst)
dut.tx_os.setimmediatevalue(0)
dut.tx_os_sig.setimmediatevalue(0)
dut.tx_os_valid.setimmediatevalue(0)
dut.cfg_tx_max_pkt_len.setimmediatevalue(0)
dut.cfg_tx_ifg.setimmediatevalue(0)
dut.cfg_tx_enable.setimmediatevalue(0)
@@ -439,6 +443,34 @@ async def run_test_oversize(dut, ifg=12):
await RisingEdge(dut.clk)
async def run_test_os(dut):
tb = TB(dut)
await tb.reset()
for sig in [False, True]:
for k in range(24):
os = 1 << k
dut.tx_os.value = os
dut.tx_os_sig.value = sig
dut.tx_os_valid.value = 1
for k in range(20):
await RisingEdge(dut.clk)
assert tb.sink.get_os() == (os, sig)
dut.tx_os_valid.value = 0
for k in range(20):
await RisingEdge(dut.clk)
for k in range(10):
await RisingEdge(dut.clk)
def size_list():
return list(range(16, 128)) + [512, 1514, 9214] + [60]*10 + [i for i in range(64, 73) for k in range(8)]
@@ -474,6 +506,9 @@ if getattr(cocotb, 'top', None) is not None:
factory.add_option("ifg", [12])
factory.generate_tests()
factory = TestFactory(run_test_os)
factory.generate_tests()
# cocotb-test

View File

@@ -47,6 +47,11 @@ logic [GBX_CNT-1:0] tx_gbx_req_sync;
logic tx_gbx_req_stall;
logic [GBX_CNT-1:0] tx_gbx_sync;
logic [23:0] tx_os;
logic tx_os_sig;
logic tx_os_valid;
logic tx_os_ready;
logic [PTP_TS_W-1:0] ptp_ts;
logic [15:0] cfg_tx_max_pkt_len;
@@ -96,6 +101,14 @@ uut (
.tx_gbx_req_stall(tx_gbx_req_stall),
.tx_gbx_sync(tx_gbx_sync),
/*
* Ordered sets
*/
.tx_os(tx_os),
.tx_os_sig(tx_os_sig),
.tx_os_valid(tx_os_valid),
.tx_os_ready(tx_os_ready),
/*
* PTP
*/