Rework termination character handling in XGMII RX modules

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich 2024-01-27 14:06:32 -08:00
parent 12744433de
commit f37bb1fc8d
2 changed files with 88 additions and 179 deletions

View File

@ -111,10 +111,9 @@ reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
reg reset_crc; reg reset_crc;
reg [3:0] last_cycle_tkeep_reg = 4'd0, last_cycle_tkeep_next; reg [1:0] term_lane_reg = 0, term_lane_d0_reg = 0;
reg term_present_reg = 1'b0;
reg [DATA_WIDTH-1:0] xgmii_rxd_masked = {DATA_WIDTH{1'b0}}; reg framing_error_reg = 1'b0;
reg [CTRL_WIDTH-1:0] xgmii_term = {CTRL_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] xgmii_rxd_d0 = {DATA_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] xgmii_rxd_d0 = {DATA_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] xgmii_rxd_d1 = {DATA_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] xgmii_rxd_d1 = {DATA_WIDTH{1'b0}};
@ -176,63 +175,11 @@ eth_crc (
.state_out(crc_next) .state_out(crc_next)
); );
// Mask input data
integer j;
always @* begin
for (j = 0; j < 4; j = j + 1) begin
xgmii_rxd_masked[j*8 +: 8] = xgmii_rxc[j] ? 8'd0 : xgmii_rxd[j*8 +: 8];
xgmii_term[j] = xgmii_rxc[j] && (xgmii_rxd[j*8 +: 8] == XGMII_TERM);
end
end
// detect control characters
reg [3:0] detect_term = 4'd0;
reg [3:0] detect_term_save;
integer i;
// mask errors to within packet
reg [3:0] control_masked;
reg [3:0] tkeep_mask;
always @* begin
casez (detect_term)
4'b0000: begin
control_masked = xgmii_rxc_d0;
tkeep_mask = 4'b1111;
end
4'bzzz1: begin
control_masked = 0;
tkeep_mask = 4'b0000;
end
4'bzz10: begin
control_masked = xgmii_rxc_d0[0];
tkeep_mask = 4'b0001;
end
4'bz100: begin
control_masked = xgmii_rxc_d0[1:0];
tkeep_mask = 4'b0011;
end
4'b1000: begin
control_masked = xgmii_rxc_d0[2:0];
tkeep_mask = 4'b0111;
end
default: begin
control_masked = xgmii_rxc_d0;
tkeep_mask = 4'b1111;
end
endcase
end
always @* begin always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
reset_crc = 1'b0; reset_crc = 1'b0;
last_cycle_tkeep_next = last_cycle_tkeep_reg;
m_axis_tdata_next = {DATA_WIDTH{1'b0}}; m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = {KEEP_WIDTH{1'b1}}; m_axis_tkeep_next = {KEEP_WIDTH{1'b1}};
m_axis_tvalid_next = 1'b0; m_axis_tvalid_next = 1'b0;
@ -251,7 +198,7 @@ always @* begin
if (xgmii_start_d2 && cfg_rx_enable) begin if (xgmii_start_d2 && cfg_rx_enable) begin
// start condition // start condition
if (control_masked) begin if (framing_error_reg) begin
// control or error characters in first data word // control or error characters in first data word
m_axis_tdata_next = {DATA_WIDTH{1'b0}}; m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = 4'h1; m_axis_tkeep_next = 4'h1;
@ -284,25 +231,20 @@ always @* begin
m_axis_tlast_next = 1'b0; m_axis_tlast_next = 1'b0;
m_axis_tuser_next[0] = 1'b0; m_axis_tuser_next[0] = 1'b0;
last_cycle_tkeep_next = tkeep_mask; if (framing_error_reg) begin
if (detect_term) begin
reset_crc = 1'b1;
end
if (control_masked) begin
// control or error characters in packet // control or error characters in packet
m_axis_tlast_next = 1'b1; m_axis_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b1; m_axis_tuser_next[0] = 1'b1;
error_bad_frame_next = 1'b1; error_bad_frame_next = 1'b1;
reset_crc = 1'b1; reset_crc = 1'b1;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else if (detect_term) begin end else if (term_present_reg) begin
if (detect_term[0]) begin reset_crc = 1'b1;
if (term_lane_reg == 0) begin
// end this cycle // end this cycle
m_axis_tkeep_next = 4'b1111; m_axis_tkeep_next = 4'b1111;
m_axis_tlast_next = 1'b1; m_axis_tlast_next = 1'b1;
if (detect_term[0] && crc_valid_save[3]) begin if (term_lane_reg == 0 && crc_valid_save[3]) begin
// CRC valid // CRC valid
end else begin end else begin
m_axis_tuser_next[0] = 1'b1; m_axis_tuser_next[0] = 1'b1;
@ -321,16 +263,16 @@ always @* begin
STATE_LAST: begin STATE_LAST: begin
// last cycle of packet // last cycle of packet
m_axis_tdata_next = xgmii_rxd_d2; m_axis_tdata_next = xgmii_rxd_d2;
m_axis_tkeep_next = last_cycle_tkeep_reg; m_axis_tkeep_next = {KEEP_WIDTH{1'b1}} >> (CTRL_WIDTH-term_lane_d0_reg);
m_axis_tvalid_next = 1'b1; m_axis_tvalid_next = 1'b1;
m_axis_tlast_next = 1'b1; m_axis_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b0; m_axis_tuser_next[0] = 1'b0;
reset_crc = 1'b1; reset_crc = 1'b1;
if ((detect_term_save[1] && crc_valid_save[0]) || if ((term_lane_d0_reg == 1 && crc_valid_save[0]) ||
(detect_term_save[2] && crc_valid_save[1]) || (term_lane_d0_reg == 2 && crc_valid_save[1]) ||
(detect_term_save[3] && crc_valid_save[2])) begin (term_lane_d0_reg == 3 && crc_valid_save[2])) begin
// CRC valid // CRC valid
end else begin end else begin
m_axis_tuser_next[0] = 1'b1; m_axis_tuser_next[0] = 1'b1;
@ -343,6 +285,8 @@ always @* begin
endcase endcase
end end
integer i;
always @(posedge clk) begin always @(posedge clk) begin
state_reg <= state_next; state_reg <= state_next;
@ -356,10 +300,19 @@ always @(posedge clk) begin
error_bad_frame_reg <= error_bad_frame_next; error_bad_frame_reg <= error_bad_frame_next;
error_bad_fcs_reg <= error_bad_fcs_next; error_bad_fcs_reg <= error_bad_fcs_next;
last_cycle_tkeep_reg <= last_cycle_tkeep_next; term_lane_reg <= 0;
term_present_reg <= 1'b0;
framing_error_reg <= xgmii_rxc != 0;
detect_term <= xgmii_term; for (i = CTRL_WIDTH-1; i >= 0; i = i - 1) begin
detect_term_save <= detect_term; if (xgmii_rxc[i] && (xgmii_rxd[i*8 +: 8] == XGMII_TERM)) begin
term_lane_reg <= i;
term_present_reg <= 1'b1;
framing_error_reg <= (xgmii_rxc & ({CTRL_WIDTH{1'b1}} >> (CTRL_WIDTH-i))) != 0;
end
end
term_lane_d0_reg <= term_lane_reg;
if (reset_crc) begin if (reset_crc) begin
crc_state <= 32'hFFFFFFFF; crc_state <= 32'hFFFFFFFF;
@ -369,7 +322,9 @@ always @(posedge clk) begin
crc_valid_save <= crc_valid; crc_valid_save <= crc_valid;
xgmii_rxd_d0 <= xgmii_rxd_masked; for (i = 0; i < CTRL_WIDTH; i = i + 1) begin
xgmii_rxd_d0[i*8 +: 8] <= xgmii_rxc[i] ? 8'd0 : xgmii_rxd[i*8 +: 8];
end
xgmii_rxc_d0 <= xgmii_rxc; xgmii_rxc_d0 <= xgmii_rxc;
xgmii_rxd_d1 <= xgmii_rxd_d0; xgmii_rxd_d1 <= xgmii_rxd_d0;
xgmii_rxd_d2 <= xgmii_rxd_d1; xgmii_rxd_d2 <= xgmii_rxd_d1;

View File

@ -112,8 +112,6 @@ reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals // datapath control signals
reg reset_crc; reg reset_crc;
reg [7:0] last_cycle_tkeep_reg = 8'd0, last_cycle_tkeep_next;
reg lanes_swapped = 1'b0; reg lanes_swapped = 1'b0;
reg [31:0] swap_rxd = 32'd0; reg [31:0] swap_rxd = 32'd0;
reg [3:0] swap_rxc = 4'd0; reg [3:0] swap_rxc = 4'd0;
@ -121,6 +119,9 @@ reg [3:0] swap_rxc_term = 4'd0;
reg [DATA_WIDTH-1:0] xgmii_rxd_masked = {DATA_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] xgmii_rxd_masked = {DATA_WIDTH{1'b0}};
reg [CTRL_WIDTH-1:0] xgmii_term = {CTRL_WIDTH{1'b0}}; reg [CTRL_WIDTH-1:0] xgmii_term = {CTRL_WIDTH{1'b0}};
reg [2:0] term_lane_reg = 0, term_lane_d0_reg = 0;
reg term_present_reg = 1'b0;
reg framing_error_reg = 1'b0;
reg [DATA_WIDTH-1:0] xgmii_rxd_d0 = {DATA_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] xgmii_rxd_d0 = {DATA_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] xgmii_rxd_d1 = {DATA_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] xgmii_rxd_d1 = {DATA_WIDTH{1'b0}};
@ -197,69 +198,11 @@ always @* begin
end end
end end
// detect control characters
reg [7:0] detect_term = 8'd0;
reg [7:0] detect_term_save = 8'd0;
integer i;
// mask errors to within packet
reg [7:0] control_masked;
reg [7:0] tkeep_mask;
always @* begin
casez (detect_term)
8'b00000000: begin
control_masked = xgmii_rxc_d0;
tkeep_mask = 8'b11111111;
end
8'bzzzzzzz1: begin
control_masked = 0;
tkeep_mask = 8'b00000000;
end
8'bzzzzzz10: begin
control_masked = xgmii_rxc_d0[0];
tkeep_mask = 8'b00000001;
end
8'bzzzzz100: begin
control_masked = xgmii_rxc_d0[1:0];
tkeep_mask = 8'b00000011;
end
8'bzzzz1000: begin
control_masked = xgmii_rxc_d0[2:0];
tkeep_mask = 8'b00000111;
end
8'bzzz10000: begin
control_masked = xgmii_rxc_d0[3:0];
tkeep_mask = 8'b00001111;
end
8'bzz100000: begin
control_masked = xgmii_rxc_d0[4:0];
tkeep_mask = 8'b00011111;
end
8'bz1000000: begin
control_masked = xgmii_rxc_d0[5:0];
tkeep_mask = 8'b00111111;
end
8'b10000000: begin
control_masked = xgmii_rxc_d0[6:0];
tkeep_mask = 8'b01111111;
end
default: begin
control_masked = xgmii_rxc_d0;
tkeep_mask = 8'b11111111;
end
endcase
end
always @* begin always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
reset_crc = 1'b0; reset_crc = 1'b0;
last_cycle_tkeep_next = last_cycle_tkeep_reg;
m_axis_tdata_next = {DATA_WIDTH{1'b0}}; m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = {KEEP_WIDTH{1'b1}}; m_axis_tkeep_next = {KEEP_WIDTH{1'b1}};
m_axis_tvalid_next = 1'b0; m_axis_tvalid_next = 1'b0;
@ -282,7 +225,7 @@ always @* begin
m_axis_tuser_next[1 +: PTP_TS_WIDTH] = (PTP_TS_WIDTH != 96 || ptp_ts_borrow_reg) ? ptp_ts_reg : ptp_ts_adj_reg; m_axis_tuser_next[1 +: PTP_TS_WIDTH] = (PTP_TS_WIDTH != 96 || ptp_ts_borrow_reg) ? ptp_ts_reg : ptp_ts_adj_reg;
end end
if (control_masked) begin if (framing_error_reg) begin
// control or error characters in first data word // control or error characters in first data word
m_axis_tdata_next = {DATA_WIDTH{1'b0}}; m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = 8'h01; m_axis_tkeep_next = 8'h01;
@ -307,29 +250,24 @@ always @* begin
m_axis_tlast_next = 1'b0; m_axis_tlast_next = 1'b0;
m_axis_tuser_next[0] = 1'b0; m_axis_tuser_next[0] = 1'b0;
last_cycle_tkeep_next = {4'b0000, tkeep_mask[7:4]}; if (framing_error_reg) begin
if (detect_term) begin
reset_crc = 1'b1;
end
if (control_masked) begin
// control or error characters in packet // control or error characters in packet
m_axis_tlast_next = 1'b1; m_axis_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b1; m_axis_tuser_next[0] = 1'b1;
error_bad_frame_next = 1'b1; error_bad_frame_next = 1'b1;
reset_crc = 1'b1; reset_crc = 1'b1;
state_next = STATE_IDLE; state_next = STATE_IDLE;
end else if (detect_term) begin end else if (term_present_reg) begin
if (detect_term[4:0]) begin reset_crc = 1'b1;
if (term_lane_reg <= 4) begin
// end this cycle // end this cycle
m_axis_tkeep_next = {tkeep_mask[3:0], 4'b1111}; m_axis_tkeep_next = {KEEP_WIDTH{1'b1}} >> (CTRL_WIDTH-4-term_lane_reg);
m_axis_tlast_next = 1'b1; m_axis_tlast_next = 1'b1;
if ((detect_term[0] && crc_valid_save[7]) || if ((term_lane_reg == 0 && crc_valid_save[7]) ||
(detect_term[1] && crc_valid[0]) || (term_lane_reg == 1 && crc_valid[0]) ||
(detect_term[2] && crc_valid[1]) || (term_lane_reg == 2 && crc_valid[1]) ||
(detect_term[3] && crc_valid[2]) || (term_lane_reg == 3 && crc_valid[2]) ||
(detect_term[4] && crc_valid[3])) begin (term_lane_reg == 4 && crc_valid[3])) begin
// CRC valid // CRC valid
end else begin end else begin
m_axis_tuser_next[0] = 1'b1; m_axis_tuser_next[0] = 1'b1;
@ -348,16 +286,16 @@ always @* begin
STATE_LAST: begin STATE_LAST: begin
// last cycle of packet // last cycle of packet
m_axis_tdata_next = xgmii_rxd_d1; m_axis_tdata_next = xgmii_rxd_d1;
m_axis_tkeep_next = last_cycle_tkeep_reg; m_axis_tkeep_next = {KEEP_WIDTH{1'b1}} >> (CTRL_WIDTH+4-term_lane_d0_reg);
m_axis_tvalid_next = 1'b1; m_axis_tvalid_next = 1'b1;
m_axis_tlast_next = 1'b1; m_axis_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b0; m_axis_tuser_next[0] = 1'b0;
reset_crc = 1'b1; reset_crc = 1'b1;
if ((detect_term_save[5] && crc_valid_save[4]) || if ((term_lane_d0_reg == 5 && crc_valid_save[4]) ||
(detect_term_save[6] && crc_valid_save[5]) || (term_lane_d0_reg == 6 && crc_valid_save[5]) ||
(detect_term_save[7] && crc_valid_save[6])) begin (term_lane_d0_reg == 7 && crc_valid_save[6])) begin
// CRC valid // CRC valid
end else begin end else begin
m_axis_tuser_next[0] = 1'b1; m_axis_tuser_next[0] = 1'b1;
@ -367,7 +305,7 @@ always @* begin
if (xgmii_start_d1) begin if (xgmii_start_d1) begin
// start condition // start condition
if (control_masked) begin if (framing_error_reg) begin
// control or error characters in first data word // control or error characters in first data word
m_axis_tdata_next = {DATA_WIDTH{1'b0}}; m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = 8'h01; m_axis_tkeep_next = 8'h01;
@ -387,6 +325,8 @@ always @* begin
endcase endcase
end end
integer i;
always @(posedge clk) begin always @(posedge clk) begin
state_reg <= state_next; state_reg <= state_next;
@ -400,10 +340,6 @@ always @(posedge clk) begin
error_bad_frame_reg <= error_bad_frame_next; error_bad_frame_reg <= error_bad_frame_next;
error_bad_fcs_reg <= error_bad_fcs_next; error_bad_fcs_reg <= error_bad_fcs_next;
last_cycle_tkeep_reg <= last_cycle_tkeep_next;
detect_term_save <= detect_term;
swap_rxd <= xgmii_rxd_masked[63:32]; swap_rxd <= xgmii_rxd_masked[63:32];
swap_rxc <= xgmii_rxc[7:4]; swap_rxc <= xgmii_rxc[7:4];
swap_rxc_term <= xgmii_term[7:4]; swap_rxc_term <= xgmii_term[7:4];
@ -419,15 +355,47 @@ always @(posedge clk) begin
ptp_ts_adj_reg[95:48] <= ptp_ts_reg[95:48] + 1; ptp_ts_adj_reg[95:48] <= ptp_ts_reg[95:48] + 1;
end end
if (xgmii_rxc[0] && xgmii_rxd[7:0] == XGMII_START) begin if (lanes_swapped) begin
lanes_swapped <= 1'b0; xgmii_rxd_d0 <= {xgmii_rxd_masked[31:0], swap_rxd};
start_packet_reg <= 2'b01; xgmii_rxc_d0 <= {xgmii_rxc[3:0], swap_rxc};
term_lane_reg <= 0;
term_present_reg <= 1'b0;
framing_error_reg <= {xgmii_rxc[3:0], swap_rxc} != 0;
for (i = CTRL_WIDTH-1; i >= 0; i = i - 1) begin
if ({xgmii_term[3:0], swap_rxc_term} & (1 << i)) begin
term_lane_reg <= i;
term_present_reg <= 1'b1;
framing_error_reg <= ({xgmii_rxc[3:0], swap_rxc} & ({CTRL_WIDTH{1'b1}} >> (CTRL_WIDTH-i))) != 0;
lanes_swapped <= 1'b0;
end
end
end else begin
xgmii_rxd_d0 <= xgmii_rxd_masked; xgmii_rxd_d0 <= xgmii_rxd_masked;
xgmii_rxc_d0 <= xgmii_rxc; xgmii_rxc_d0 <= xgmii_rxc;
term_lane_reg <= 0;
term_present_reg <= 1'b0;
framing_error_reg <= xgmii_rxc != 0;
for (i = CTRL_WIDTH-1; i >= 0; i = i - 1) begin
if (xgmii_rxc[i] && (xgmii_rxd[i*8 +: 8] == XGMII_TERM)) begin
term_lane_reg <= i;
term_present_reg <= 1'b1;
framing_error_reg <= (xgmii_rxc & ({CTRL_WIDTH{1'b1}} >> (CTRL_WIDTH-i))) != 0;
lanes_swapped <= 1'b0;
end
end
end
term_lane_d0_reg <= term_lane_reg;
if (xgmii_rxc[0] && xgmii_rxd[7:0] == XGMII_START) begin
lanes_swapped <= 1'b0;
start_packet_reg <= 2'b01;
xgmii_start_d0 <= 1'b1; xgmii_start_d0 <= 1'b1;
detect_term <= xgmii_term;
if (PTP_TS_WIDTH == 96) begin if (PTP_TS_WIDTH == 96) begin
ptp_ts_reg[45:0] <= ptp_ts[45:0] + (PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS); ptp_ts_reg[45:0] <= ptp_ts[45:0] + (PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS);
@ -438,29 +406,15 @@ always @(posedge clk) begin
end else if (xgmii_rxc[4] && xgmii_rxd[39:32] == XGMII_START) begin end else if (xgmii_rxc[4] && xgmii_rxd[39:32] == XGMII_START) begin
lanes_swapped <= 1'b1; lanes_swapped <= 1'b1;
start_packet_reg <= 2'b10; start_packet_reg <= 2'b10;
xgmii_rxd_d0 <= {xgmii_rxd_masked[31:0], swap_rxd};
xgmii_rxc_d0 <= {xgmii_rxc[3:0], swap_rxc};
xgmii_start_swap <= 1'b1; xgmii_start_swap <= 1'b1;
detect_term <= {xgmii_term[3:0], swap_rxc_term};
if (PTP_TS_WIDTH == 96) begin if (PTP_TS_WIDTH == 96) begin
ptp_ts_reg[45:0] <= ptp_ts[45:0] + (((PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS) * 3) >> 1); ptp_ts_reg[45:0] <= ptp_ts[45:0] + (((PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS) * 3) >> 1);
ptp_ts_reg[95:48] <= ptp_ts[95:48]; ptp_ts_reg[95:48] <= ptp_ts[95:48];
end else begin end else begin
ptp_ts_reg <= ptp_ts + (((PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS) * 3) >> 1); ptp_ts_reg <= ptp_ts + (((PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS) * 3) >> 1);
end end
end else if (lanes_swapped) begin
xgmii_rxd_d0 <= {xgmii_rxd_masked[31:0], swap_rxd};
xgmii_rxc_d0 <= {xgmii_rxc[3:0], swap_rxc};
detect_term <= {xgmii_term[3:0], swap_rxc_term};
end else begin
xgmii_rxd_d0 <= xgmii_rxd_masked;
xgmii_rxc_d0 <= xgmii_rxc;
detect_term <= xgmii_term;
end end
if (reset_crc) begin if (reset_crc) begin