From 62c544444bb89afacddfe8087baa335e7f232d41 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Thu, 18 Jun 2026 22:02:58 -0700 Subject: [PATCH] eth: Support ordered sets in XGMII-BASE-R encode/decode logic Signed-off-by: Alex Forencich --- src/eth/rtl/taxi_eth_phy_10g_rx.sv | 7 ++ src/eth/rtl/taxi_eth_phy_10g_tx.sv | 8 +++ src/eth/rtl/taxi_xgmii_baser_dec.sv | 66 +++++++++++++++++++ src/eth/rtl/taxi_xgmii_baser_enc.sv | 32 ++++++++- .../test_taxi_xgmii_baser_dec.py | 30 +++++++++ .../test_taxi_xgmii_baser_enc.py | 31 +++++++++ 6 files changed, 173 insertions(+), 1 deletion(-) diff --git a/src/eth/rtl/taxi_eth_phy_10g_rx.sv b/src/eth/rtl/taxi_eth_phy_10g_rx.sv index 9ea7b02..2ac62b1 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_rx.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_rx.sv @@ -146,6 +146,13 @@ xgmii_baser_dec_inst ( .xgmii_rxc(xgmii_rxc), .xgmii_rx_valid(xgmii_rx_valid), + /* + * Ordered sets + */ + .rx_os(), + .rx_os_sig(), + .rx_os_valid(), + /* * Status */ diff --git a/src/eth/rtl/taxi_eth_phy_10g_tx.sv b/src/eth/rtl/taxi_eth_phy_10g_tx.sv index 4f8c8f5..b153454 100644 --- a/src/eth/rtl/taxi_eth_phy_10g_tx.sv +++ b/src/eth/rtl/taxi_eth_phy_10g_tx.sv @@ -97,6 +97,14 @@ xgmii_baser_enc_inst ( .encoded_tx_hdr_valid(encoded_tx_hdr_valid), .tx_gbx_sync_out(tx_gbx_sync_int), + /* + * Ordered sets + */ + .tx_os('0), + .tx_os_sig(1'b0), + .tx_os_valid(1'b0), + .tx_os_ready(), + /* * Status */ diff --git a/src/eth/rtl/taxi_xgmii_baser_dec.sv b/src/eth/rtl/taxi_xgmii_baser_dec.sv index c776f77..e980a5b 100644 --- a/src/eth/rtl/taxi_xgmii_baser_dec.sv +++ b/src/eth/rtl/taxi_xgmii_baser_dec.sv @@ -41,6 +41,13 @@ module taxi_xgmii_baser_dec # output wire logic [CTRL_W-1:0] xgmii_rxc, output wire logic xgmii_rx_valid, + /* + * 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, + /* * Status */ @@ -130,6 +137,10 @@ logic [DATA_W_INT-1:0] xgmii_rxd_reg = '0, xgmii_rxd_next; logic [CTRL_W_INT-1:0] xgmii_rxc_reg = '0, xgmii_rxc_next; logic [SEG_CNT-1:0] xgmii_rx_valid_reg = '0, xgmii_rx_valid_next; +logic [23:0] rx_os_reg = '0, rx_os_next; +logic rx_os_sig_reg = 1'b0, rx_os_sig_next; +logic rx_os_valid_reg = 1'b0, rx_os_valid_next; + logic rx_bad_block_reg = 1'b0, rx_bad_block_next; logic rx_sequence_error_reg = 1'b0, rx_sequence_error_next; logic frame_reg = 1'b0, frame_next; @@ -138,6 +149,10 @@ assign xgmii_rxd = xgmii_rxd_reg[DATA_W-1:0]; assign xgmii_rxc = xgmii_rxc_reg[CTRL_W-1:0]; assign xgmii_rx_valid = GBX_IF_EN ? xgmii_rx_valid_reg[0] : 1'b1; +assign rx_os = rx_os_reg; +assign rx_os_sig = rx_os_sig_reg; +assign rx_os_valid = rx_os_valid_reg; + assign rx_bad_block = rx_bad_block_reg; assign rx_sequence_error = rx_sequence_error_reg; @@ -177,6 +192,11 @@ always_comb begin xgmii_rxd_next = {CTRL_W_INT{XGMII_ERROR}}; xgmii_rxc_next = '1; xgmii_rx_valid_next = '0; + + rx_os_next = '0; + rx_os_sig_next = 1'b0; + rx_os_valid_next = 1'b0; + rx_bad_block_next = 1'b0; rx_sequence_error_next = 1'b0; frame_next = frame_reg; @@ -263,9 +283,19 @@ always_comb begin xgmii_rxc_next[3:0] = 4'hf; xgmii_rxd_next[63:40] = encoded_rx_data_int[63:40]; xgmii_rxc_next[7:4] = 4'h1; + rx_os_next[7:0] = encoded_rx_data_int[63:56]; + rx_os_next[15:8] = encoded_rx_data_int[55:48]; + rx_os_next[23:16] = encoded_rx_data_int[47:40]; if (encoded_rx_data_int[39:36] == O_SEQ_OS) begin xgmii_rxd_next[39:32] = XGMII_SEQ_OS; rx_bad_block_next = decode_err[3:0] != 0; + rx_os_sig_next = 1'b0; + rx_os_valid_next = 1'b1; + end else if (encoded_rx_data_int[39:36] == O_SIG_OS) begin + xgmii_rxd_next[39:32] = XGMII_SIG_OS; + rx_bad_block_next = decode_err[3:0] != 0; + rx_os_sig_next = 1'b1; + rx_os_valid_next = 1'b1; end else begin xgmii_rxd_next[39:32] = XGMII_ERROR; rx_bad_block_next = 1'b1; @@ -283,9 +313,19 @@ always_comb begin // D7 D6 D5 O0 D3 D2 D1 BT xgmii_rxd_next[31:8] = encoded_rx_data_int[31:8]; xgmii_rxc_next[3:0] = 4'h1; + rx_os_next[7:0] = encoded_rx_data_int[31:24]; + rx_os_next[15:8] = encoded_rx_data_int[23:16]; + rx_os_next[23:16] = encoded_rx_data_int[15:8]; if (encoded_rx_data_int[35:32] == O_SEQ_OS) begin xgmii_rxd_next[7:0] = XGMII_SEQ_OS; rx_bad_block_next = 1'b0; + rx_os_sig_next = 1'b0; + rx_os_valid_next = 1'b1; + end else if (encoded_rx_data_int[35:32] == O_SIG_OS) begin + xgmii_rxd_next[7:0] = XGMII_SIG_OS; + rx_bad_block_next = 1'b0; + rx_os_sig_next = 1'b1; + rx_os_valid_next = 1'b1; end else begin xgmii_rxd_next[7:0] = XGMII_ERROR; rx_bad_block_next = 1'b1; @@ -302,14 +342,25 @@ always_comb begin xgmii_rxc_next[3:0] = 4'h1; if (encoded_rx_data_int[35:32] == O_SEQ_OS) begin xgmii_rxd_next[7:0] = XGMII_SEQ_OS; + end else if (encoded_rx_data_int[35:32] == O_SIG_OS) begin + xgmii_rxd_next[7:0] = XGMII_SIG_OS; end else begin xgmii_rxd_next[7:0] = XGMII_ERROR; rx_bad_block_next = 1'b1; end xgmii_rxd_next[63:40] = encoded_rx_data_int[63:40]; xgmii_rxc_next[7:4] = 4'h1; + rx_os_next[7:0] = encoded_rx_data_int[63:56]; + rx_os_next[15:8] = encoded_rx_data_int[55:48]; + rx_os_next[23:16] = encoded_rx_data_int[47:40]; if (encoded_rx_data_int[39:36] == O_SEQ_OS) begin xgmii_rxd_next[39:32] = XGMII_SEQ_OS; + rx_os_sig_next = 1'b0; + rx_os_valid_next = 1'b1; + end else if (encoded_rx_data_int[39:36] == O_SIG_OS) begin + xgmii_rxd_next[39:32] = XGMII_SIG_OS; + rx_os_sig_next = 1'b1; + rx_os_valid_next = 1'b1; end else begin xgmii_rxd_next[39:32] = XGMII_ERROR; rx_bad_block_next = 1'b1; @@ -327,9 +378,19 @@ always_comb begin // C7 C6 C5 C4 O0 D3 D2 D1 BT xgmii_rxd_next[31:8] = encoded_rx_data_int[31:8]; xgmii_rxc_next[3:0] = 4'h1; + rx_os_next[7:0] = encoded_rx_data_int[31:24]; + rx_os_next[15:8] = encoded_rx_data_int[23:16]; + rx_os_next[23:16] = encoded_rx_data_int[15:8]; if (encoded_rx_data_int[35:32] == O_SEQ_OS) begin xgmii_rxd_next[7:0] = XGMII_SEQ_OS; rx_bad_block_next = decode_err[7:4] != 0; + rx_os_sig_next = 1'b0; + rx_os_valid_next = 1'b1; + end else if (encoded_rx_data_int[35:32] == O_SIG_OS) begin + xgmii_rxd_next[7:0] = XGMII_SIG_OS; + rx_bad_block_next = decode_err[7:4] != 0; + rx_os_sig_next = 1'b1; + rx_os_valid_next = 1'b1; end else begin xgmii_rxd_next[7:0] = XGMII_ERROR; rx_bad_block_next = 1'b1; @@ -453,12 +514,17 @@ always_ff @(posedge clk) begin xgmii_rxc_reg <= xgmii_rxc_next; xgmii_rx_valid_reg <= xgmii_rx_valid_next; + rx_os_reg <= rx_os_next; + rx_os_sig_reg <= rx_os_sig_next; + rx_os_valid_reg <= rx_os_valid_next; + rx_bad_block_reg <= rx_bad_block_next; rx_sequence_error_reg <= rx_sequence_error_next; frame_reg <= frame_next; if (rst) begin xgmii_rx_valid_reg <= '0; + rx_os_valid_reg <= 1'b0; frame_reg <= 1'b0; end end diff --git a/src/eth/rtl/taxi_xgmii_baser_enc.sv b/src/eth/rtl/taxi_xgmii_baser_enc.sv index 9c7d8fc..78b43b0 100644 --- a/src/eth/rtl/taxi_xgmii_baser_enc.sv +++ b/src/eth/rtl/taxi_xgmii_baser_enc.sv @@ -44,6 +44,14 @@ module taxi_xgmii_baser_enc # output wire logic encoded_tx_hdr_valid, output wire logic [GBX_CNT-1:0] tx_gbx_sync_out, + /* + * 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, + /* * Status */ @@ -136,6 +144,8 @@ logic [HDR_W-1:0] encoded_tx_hdr_reg = '0, encoded_tx_hdr_next; logic encoded_tx_hdr_valid_reg = 1'b0, encoded_tx_hdr_valid_next; logic [GBX_CNT-1:0] tx_gbx_sync_reg = '0, tx_gbx_sync_next; +logic tx_os_ready_reg = 1'b0, tx_os_ready_next; + logic tx_bad_block_reg = 1'b0, tx_bad_block_next; assign encoded_tx_data = encoded_tx_data_reg[DATA_W-1:0]; @@ -144,6 +154,8 @@ assign encoded_tx_hdr = encoded_tx_hdr_reg; assign encoded_tx_hdr_valid = USE_HDR_VLD ? encoded_tx_hdr_valid_reg : 1'b1; assign tx_gbx_sync_out = GBX_IF_EN ? tx_gbx_sync_reg : '0; +assign tx_os_ready = tx_os_ready_reg; + assign tx_bad_block = tx_bad_block_reg; if (DATA_W == 64) begin : repack_in @@ -187,6 +199,8 @@ always_comb begin encoded_tx_hdr_valid_next = '0; tx_gbx_sync_next = '0; + tx_os_ready_next = 1'b0; + tx_bad_block_next = 1'b0; for (integer i = 0; i < CTRL_W_INT; i = i + 1) begin @@ -321,7 +335,21 @@ always_comb begin tx_bad_block_next = 1'b0; end else if (xgmii_txc_int == 8'hff) begin // all control - encoded_tx_data_next = {encoded_ctrl, BLOCK_TYPE_CTRL}; + if (tx_os_valid && xgmii_txd_int[7:0] == XGMII_IDLE) begin + // assume all idles, replace with ordered sets + encoded_tx_data_next[7:0] = BLOCK_TYPE_OS_04; + encoded_tx_data_next[15:8] = tx_os[23:16]; + encoded_tx_data_next[23:16] = tx_os[15:8]; + encoded_tx_data_next[31:24] = tx_os[7:0]; + encoded_tx_data_next[35:32] = tx_os_sig ? O_SIG_OS : O_SEQ_OS; + encoded_tx_data_next[39:36] = tx_os_sig ? O_SIG_OS : O_SEQ_OS; + encoded_tx_data_next[47:40] = tx_os[23:16]; + encoded_tx_data_next[55:48] = tx_os[15:8]; + encoded_tx_data_next[63:56] = tx_os[7:0]; + tx_os_ready_next = 1'b1; + end else begin + encoded_tx_data_next = {encoded_ctrl, BLOCK_TYPE_CTRL}; + end tx_bad_block_next = encode_err != 0; end else begin // no corresponding block format @@ -347,6 +375,8 @@ always_ff @(posedge clk) begin encoded_tx_hdr_valid_reg <= encoded_tx_hdr_valid_next; tx_gbx_sync_reg <= tx_gbx_sync_next; + tx_os_ready_reg <= tx_os_ready_next; + tx_bad_block_reg <= tx_bad_block_next; end diff --git a/src/eth/tb/taxi_xgmii_baser_dec/test_taxi_xgmii_baser_dec.py b/src/eth/tb/taxi_xgmii_baser_dec/test_taxi_xgmii_baser_dec.py index 94ba863..9286e40 100644 --- a/src/eth/tb/taxi_xgmii_baser_dec/test_taxi_xgmii_baser_dec.py +++ b/src/eth/tb/taxi_xgmii_baser_dec/test_taxi_xgmii_baser_dec.py @@ -176,6 +176,33 @@ async def run_test_alignment(dut, payload_data=None, ifg=12, enable_dic=True, 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 @@ -205,6 +232,9 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("force_offset_start", [False, True]) factory.generate_tests() + factory = TestFactory(run_test_os) + factory.generate_tests() + # cocotb-test diff --git a/src/eth/tb/taxi_xgmii_baser_enc/test_taxi_xgmii_baser_enc.py b/src/eth/tb/taxi_xgmii_baser_enc/test_taxi_xgmii_baser_enc.py index 511f6ee..2e1d39e 100644 --- a/src/eth/tb/taxi_xgmii_baser_enc/test_taxi_xgmii_baser_enc.py +++ b/src/eth/tb/taxi_xgmii_baser_enc/test_taxi_xgmii_baser_enc.py @@ -176,6 +176,34 @@ async def run_test_alignment(dut, payload_data=None, ifg=12, enable_dic=True, 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(60, 128)) + [512, 1514, 9214] + [60]*10 @@ -206,6 +234,9 @@ if getattr(cocotb, 'top', None) is not None: factory.add_option("force_offset_start", [False, True]) factory.generate_tests() + factory = TestFactory(run_test_os) + factory.generate_tests() + # cocotb-test