eth: Add support for SGMII symbol replication to 8-bit AXIS/BASE-X decode module

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich
2026-07-09 11:51:20 -07:00
parent 1636dbecc4
commit d0ca158189
4 changed files with 96 additions and 24 deletions

View File

@@ -20,7 +20,8 @@ module taxi_axis_basex_rx_8 #
parameter DATA_W = 8,
parameter CTRL_W = (DATA_W/8),
parameter logic GBX_IF_EN = 1'b0,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
parameter logic PTP_TS_EN = 1'b0,
parameter PTP_TS_W = 96
)
@@ -58,7 +59,9 @@ module taxi_axis_basex_rx_8 #
* Configuration
*/
input wire logic [15:0] cfg_rx_max_pkt_len = 16'd1518-1,
input wire logic cfg_rx_enable,
input wire logic cfg_rx_enable = 1'b1,
input wire logic cfg_rx_sgmii_en = 1'b1,
input wire logic [1:0] cfg_rx_sgmii_speed = 2'b10,
/*
* Status
@@ -157,6 +160,9 @@ logic [15:0] frame_len_lim_reg = '0, frame_len_lim_next;
logic frame_len_lim_check_reg = '0, frame_len_lim_check_next;
logic odd_reg = 1'b0, odd_next;
logic [6:0] rep_cnt_reg = '0;
logic rep_stall_reg = 1'b0;
logic [DATA_W-1:0] m_axis_rx_tdata_reg = '0, m_axis_rx_tdata_next;
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;
@@ -164,6 +170,7 @@ logic m_axis_rx_tuser_reg = 1'b0, m_axis_rx_tuser_next;
logic [15:0] rx_an_cfg_reg = '0;
logic rx_an_cfg_valid_reg = 1'b0;
logic an_cfg_match_reg = 1'b0;
logic [1:0] an_ability_match_reg = '0;
logic [1:0] an_ack_match_reg = '0;
logic [1:0] an_idle_match_reg = '0;
@@ -288,6 +295,9 @@ always_comb begin
if (GBX_IF_EN && !encoded_rx_data_valid) begin
// data from gearbox not valid - hold state
state_next = state_reg;
end else if (SGMII_EN && rep_stall_reg) begin
// SGMII stall - hold state
state_next = state_reg;
end else begin
odd_next = !odd_reg;
@@ -341,7 +351,7 @@ always_comb begin
pre_ok_next = 1'b1;
if (encoded_rx_data_k_d0_reg && encoded_rx_data_d0_reg == CTRL_S && !encoded_rx_data_k) begin
if (input_start_d0_reg && !encoded_rx_data_k) begin
state_next = STATE_PREAMBLE;
end else begin
state_next = STATE_IDLE;
@@ -504,13 +514,15 @@ always_ff @(posedge clk) begin
start_packet_int_reg <= 1'b1;
end
encoded_rx_data_d0_reg <= encoded_rx_data;
encoded_rx_data_d1_reg <= encoded_rx_data_d0_reg;
encoded_rx_data_d2_reg <= encoded_rx_data_d1_reg;
encoded_rx_data_d3_reg <= encoded_rx_data_d2_reg;
encoded_rx_data_d4_reg <= encoded_rx_data_d3_reg;
if (!SGMII_EN || !rep_stall_reg) begin
encoded_rx_data_d0_reg <= encoded_rx_data;
encoded_rx_data_d1_reg <= encoded_rx_data_d0_reg;
encoded_rx_data_d2_reg <= encoded_rx_data_d1_reg;
encoded_rx_data_d3_reg <= encoded_rx_data_d2_reg;
encoded_rx_data_d4_reg <= encoded_rx_data_d3_reg;
encoded_rx_data_k_d0_reg <= encoded_rx_data_k;
encoded_rx_data_k_d0_reg <= encoded_rx_data_k;
end
input_k28p5_d0_reg <= 1'b0;
input_i_d0_reg <= 1'b0;
@@ -540,19 +552,21 @@ always_ff @(posedge clk) begin
end
if (AN_EN && input_c_d0_reg) begin
rx_an_cfg_reg[7:0] <= encoded_rx_data;
an_cfg_match_reg <= rx_an_cfg_reg[7:0] == encoded_rx_data;
input_c_d1_reg <= encoded_rx_data_k == 1'b0;
an_idle_match_reg <= '0;
end
if (AN_EN && input_c_d1_reg) begin
rx_an_cfg_reg <= {encoded_rx_data, encoded_rx_data_d0_reg};
rx_an_cfg_reg[15:8] <= encoded_rx_data;
rx_an_cfg_valid_reg <= encoded_rx_data_k == 1'b0;
if (((rx_an_cfg_reg ^ {encoded_rx_data, encoded_rx_data_d0_reg}) & ~16'h4000) == 0) begin
if (an_cfg_match_reg && ((rx_an_cfg_reg[15:8] ^ encoded_rx_data) & ~8'h40) == 0) begin
an_ability_match_reg <= {an_ability_match_reg[0], 1'b1};
end else begin
an_ability_match_reg <= '0;
end
if (rx_an_cfg_reg[14] && rx_an_cfg_reg == {encoded_rx_data, encoded_rx_data_d0_reg}) begin
if (an_cfg_match_reg && rx_an_cfg_reg[14] && rx_an_cfg_reg[15:8] == encoded_rx_data) begin
an_ack_match_reg <= {an_ack_match_reg[0], 1'b1};
end else begin
an_ack_match_reg <= '0;
@@ -576,6 +590,35 @@ always_ff @(posedge clk) begin
end else if (update_crc) begin
crc_state_reg <= crc_state;
end
if (SGMII_EN && cfg_rx_sgmii_en) begin
if (encoded_rx_data != encoded_rx_data_d0_reg || encoded_rx_data_k) begin
rep_stall_reg <= !rep_stall_reg;
case (cfg_rx_sgmii_speed)
2'b00: rep_cnt_reg <= 98; // 10 Mbps
2'b01: rep_cnt_reg <= 8; // 100 Mbps
default: begin
rep_cnt_reg <= 0;
rep_stall_reg <= 1'b0;
end
endcase
end else if (rep_cnt_reg == 0) begin
case (cfg_rx_sgmii_speed)
2'b00: rep_cnt_reg <= 99; // 10 Mbps
2'b01: rep_cnt_reg <= 9; // 100 Mbps
2'b10: rep_cnt_reg <= 0; // 1 Gbps
default: rep_cnt_reg <= 0;
endcase
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
stat_rx_byte_reg <= stat_rx_byte_next;
@@ -603,6 +646,9 @@ always_ff @(posedge clk) begin
input_c_d1_reg <= 1'b0;
input_start_d0_reg <= 1'b0;
rep_cnt_reg <= '0;
rep_stall_reg <= 1'b0;
m_axis_rx_tvalid_reg <= 1'b0;
rx_an_cfg_valid_reg <= 1'b0;

View File

@@ -36,7 +36,8 @@ VERILOG_SOURCES := $(call uniq_base,$(call process_f_files,$(VERILOG_SOURCES)))
# module parameters
export PARAM_DATA_W := 8
export PARAM_GBX_IF_EN := 0
export PARAM_AN_EN := 1
export PARAM_SGMII_EN := 1
export PARAM_AN_EN := $(PARAM_SGMII_EN)
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, sgmii_speed=None):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
@@ -65,6 +65,21 @@ class TB:
dut.cfg_rx_max_pkt_len.setimmediatevalue(0)
dut.cfg_rx_enable.setimmediatevalue(0)
if sgmii_speed is not None:
dut.cfg_rx_sgmii_en.setimmediatevalue(1)
dut.cfg_rx_sgmii_speed.setimmediatevalue(sgmii_speed)
if sgmii_speed == 0:
self.source.set_gmii_rep_count(99) # 10 Mbps
elif sgmii_speed == 1:
self.source.set_gmii_rep_count(9) # 100 Mbps
elif sgmii_speed == 2:
self.source.set_gmii_rep_count(0) # 1 Gbps
else:
self.source.set_gmii_rep_count(0)
else:
dut.cfg_rx_sgmii_en.setimmediatevalue(0)
dut.cfg_rx_sgmii_speed.setimmediatevalue(0b10)
self.source.set_gmii_rep_count(0)
self.stats = {}
self.stats["stat_rx_byte"] = 0
@@ -109,9 +124,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, pre_len=8):
async def run_test(dut, gbx_cfg=None, sgmii_speed=None, payload_lengths=None, payload_data=None, ifg=12, pre_len=8):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, sgmii_speed)
tb.source.ifg = ifg
tb.dut.cfg_rx_max_pkt_len.value = 9218-1
@@ -176,9 +191,9 @@ async def run_test(dut, gbx_cfg=None, payload_lengths=None, payload_data=None, i
await RisingEdge(dut.clk)
async def run_test_oversize(dut, gbx_cfg=None, ifg=12):
async def run_test_oversize(dut, gbx_cfg=None, sgmii_speed=None, ifg=12):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, sgmii_speed)
tb.source.ifg = ifg
tb.dut.cfg_rx_max_pkt_len.value = 1518-1
@@ -265,9 +280,9 @@ async def run_test_oversize(dut, gbx_cfg=None, ifg=12):
await RisingEdge(dut.clk)
async def run_test_an(dut, gbx_cfg=None):
async def run_test_an(dut, gbx_cfg=None, sgmii_speed=None):
tb = TB(dut, gbx_cfg)
tb = TB(dut, gbx_cfg, sgmii_speed)
await tb.reset()
@@ -319,17 +334,20 @@ if getattr(cocotb, 'top', None) is not None:
factory = TestFactory(run_test)
factory.add_option("payload_lengths", [size_list])
factory.add_option("payload_data", [incrementing_payload])
factory.add_option("ifg", list(range(0, 13)))
# factory.add_option("ifg", list(range(0, 13)))
factory.add_option("pre_len", [8, 7])
factory.add_option("sgmii_speed", [None, 1, 2])
factory.add_option("gbx_cfg", gbx_cfgs)
factory.generate_tests()
factory = TestFactory(run_test_oversize)
factory.add_option("ifg", list(range(0, 13)))
# factory.add_option("ifg", list(range(0, 13)))
factory.add_option("sgmii_speed", [None, 1, 2])
factory.add_option("gbx_cfg", gbx_cfgs)
factory.generate_tests()
factory = TestFactory(run_test_an)
factory.add_option("sgmii_speed", [None, 1, 2])
factory.add_option("gbx_cfg", gbx_cfgs)
factory.generate_tests()
@@ -374,7 +392,8 @@ def test_taxi_axis_basex_rx_8(request, gbx_en):
parameters['DATA_W'] = 8
parameters['GBX_IF_EN'] = gbx_en
parameters['AN_EN'] = 1
parameters['SGMII_EN'] = 1
parameters['AN_EN'] = parameters['SGMII_EN']
parameters['PTP_TS_EN'] = 1
parameters['PTP_TS_FMT_TOD'] = 1
parameters['PTP_TS_W'] = 96 if parameters['PTP_TS_FMT_TOD'] else 64

View File

@@ -21,7 +21,8 @@ module test_taxi_axis_basex_rx_8 #
parameter DATA_W = 8,
parameter CTRL_W = DATA_W / 8,
parameter logic GBX_IF_EN = 1'b0,
parameter logic AN_EN = 1'b1,
parameter logic SGMII_EN = 1'b1,
parameter logic AN_EN = SGMII_EN,
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
@@ -50,6 +51,8 @@ logic [PTP_TS_W-1:0] ptp_ts;
logic [15:0] cfg_rx_max_pkt_len;
logic cfg_rx_enable;
logic cfg_rx_sgmii_en;
logic [1:0] cfg_rx_sgmii_speed;
logic rx_start_packet;
logic stat_rx_byte;
@@ -72,6 +75,7 @@ taxi_axis_basex_rx_8 #(
.DATA_W(DATA_W),
.CTRL_W(CTRL_W),
.GBX_IF_EN(GBX_IF_EN),
.SGMII_EN(SGMII_EN),
.AN_EN(AN_EN),
.PTP_TS_EN(PTP_TS_EN),
.PTP_TS_W(PTP_TS_W)
@@ -111,6 +115,8 @@ uut (
*/
.cfg_rx_max_pkt_len(cfg_rx_max_pkt_len),
.cfg_rx_enable(cfg_rx_enable),
.cfg_rx_sgmii_en(cfg_rx_sgmii_en),
.cfg_rx_sgmii_speed(cfg_rx_sgmii_speed),
/*
* Status