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
reg reset_crc;
reg [3:0] last_cycle_tkeep_reg = 4'd0, last_cycle_tkeep_next;
reg [DATA_WIDTH-1:0] xgmii_rxd_masked = {DATA_WIDTH{1'b0}};
reg [CTRL_WIDTH-1:0] xgmii_term = {CTRL_WIDTH{1'b0}};
reg [1: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_d1 = {DATA_WIDTH{1'b0}};
@ -176,63 +175,11 @@ eth_crc (
.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
state_next = STATE_IDLE;
reset_crc = 1'b0;
last_cycle_tkeep_next = last_cycle_tkeep_reg;
m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = {KEEP_WIDTH{1'b1}};
m_axis_tvalid_next = 1'b0;
@ -251,7 +198,7 @@ always @* begin
if (xgmii_start_d2 && cfg_rx_enable) begin
// start condition
if (control_masked) begin
if (framing_error_reg) begin
// control or error characters in first data word
m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = 4'h1;
@ -284,25 +231,20 @@ always @* begin
m_axis_tlast_next = 1'b0;
m_axis_tuser_next[0] = 1'b0;
last_cycle_tkeep_next = tkeep_mask;
if (detect_term) begin
reset_crc = 1'b1;
end
if (control_masked) begin
if (framing_error_reg) begin
// control or error characters in packet
m_axis_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b1;
error_bad_frame_next = 1'b1;
reset_crc = 1'b1;
state_next = STATE_IDLE;
end else if (detect_term) begin
if (detect_term[0]) begin
end else if (term_present_reg) begin
reset_crc = 1'b1;
if (term_lane_reg == 0) begin
// end this cycle
m_axis_tkeep_next = 4'b1111;
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
end else begin
m_axis_tuser_next[0] = 1'b1;
@ -321,16 +263,16 @@ always @* begin
STATE_LAST: begin
// last cycle of packet
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_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b0;
reset_crc = 1'b1;
if ((detect_term_save[1] && crc_valid_save[0]) ||
(detect_term_save[2] && crc_valid_save[1]) ||
(detect_term_save[3] && crc_valid_save[2])) begin
if ((term_lane_d0_reg == 1 && crc_valid_save[0]) ||
(term_lane_d0_reg == 2 && crc_valid_save[1]) ||
(term_lane_d0_reg == 3 && crc_valid_save[2])) begin
// CRC valid
end else begin
m_axis_tuser_next[0] = 1'b1;
@ -343,6 +285,8 @@ always @* begin
endcase
end
integer i;
always @(posedge clk) begin
state_reg <= state_next;
@ -356,10 +300,19 @@ always @(posedge clk) begin
error_bad_frame_reg <= error_bad_frame_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;
detect_term_save <= detect_term;
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;
end
end
term_lane_d0_reg <= term_lane_reg;
if (reset_crc) begin
crc_state <= 32'hFFFFFFFF;
@ -369,7 +322,9 @@ always @(posedge clk) begin
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_rxd_d1 <= xgmii_rxd_d0;
xgmii_rxd_d2 <= xgmii_rxd_d1;

View File

@ -112,8 +112,6 @@ reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg reset_crc;
reg [7:0] last_cycle_tkeep_reg = 8'd0, last_cycle_tkeep_next;
reg lanes_swapped = 1'b0;
reg [31:0] swap_rxd = 32'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 [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_d1 = {DATA_WIDTH{1'b0}};
@ -197,69 +198,11 @@ always @* begin
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
state_next = STATE_IDLE;
reset_crc = 1'b0;
last_cycle_tkeep_next = last_cycle_tkeep_reg;
m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = {KEEP_WIDTH{1'b1}};
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;
end
if (control_masked) begin
if (framing_error_reg) begin
// control or error characters in first data word
m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = 8'h01;
@ -307,29 +250,24 @@ always @* begin
m_axis_tlast_next = 1'b0;
m_axis_tuser_next[0] = 1'b0;
last_cycle_tkeep_next = {4'b0000, tkeep_mask[7:4]};
if (detect_term) begin
reset_crc = 1'b1;
end
if (control_masked) begin
if (framing_error_reg) begin
// control or error characters in packet
m_axis_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b1;
error_bad_frame_next = 1'b1;
reset_crc = 1'b1;
state_next = STATE_IDLE;
end else if (detect_term) begin
if (detect_term[4:0]) begin
end else if (term_present_reg) begin
reset_crc = 1'b1;
if (term_lane_reg <= 4) begin
// 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;
if ((detect_term[0] && crc_valid_save[7]) ||
(detect_term[1] && crc_valid[0]) ||
(detect_term[2] && crc_valid[1]) ||
(detect_term[3] && crc_valid[2]) ||
(detect_term[4] && crc_valid[3])) begin
if ((term_lane_reg == 0 && crc_valid_save[7]) ||
(term_lane_reg == 1 && crc_valid[0]) ||
(term_lane_reg == 2 && crc_valid[1]) ||
(term_lane_reg == 3 && crc_valid[2]) ||
(term_lane_reg == 4 && crc_valid[3])) begin
// CRC valid
end else begin
m_axis_tuser_next[0] = 1'b1;
@ -348,16 +286,16 @@ always @* begin
STATE_LAST: begin
// last cycle of packet
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_tlast_next = 1'b1;
m_axis_tuser_next[0] = 1'b0;
reset_crc = 1'b1;
if ((detect_term_save[5] && crc_valid_save[4]) ||
(detect_term_save[6] && crc_valid_save[5]) ||
(detect_term_save[7] && crc_valid_save[6])) begin
if ((term_lane_d0_reg == 5 && crc_valid_save[4]) ||
(term_lane_d0_reg == 6 && crc_valid_save[5]) ||
(term_lane_d0_reg == 7 && crc_valid_save[6])) begin
// CRC valid
end else begin
m_axis_tuser_next[0] = 1'b1;
@ -367,7 +305,7 @@ always @* begin
if (xgmii_start_d1) begin
// start condition
if (control_masked) begin
if (framing_error_reg) begin
// control or error characters in first data word
m_axis_tdata_next = {DATA_WIDTH{1'b0}};
m_axis_tkeep_next = 8'h01;
@ -387,6 +325,8 @@ always @* begin
endcase
end
integer i;
always @(posedge clk) begin
state_reg <= state_next;
@ -400,10 +340,6 @@ always @(posedge clk) begin
error_bad_frame_reg <= error_bad_frame_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_rxc <= xgmii_rxc[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;
end
if (xgmii_rxc[0] && xgmii_rxd[7:0] == XGMII_START) begin
if (lanes_swapped) begin
xgmii_rxd_d0 <= {xgmii_rxd_masked[31:0], swap_rxd};
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;
start_packet_reg <= 2'b01;
end
end
end else begin
xgmii_rxd_d0 <= xgmii_rxd_masked;
xgmii_rxc_d0 <= xgmii_rxc;
xgmii_start_d0 <= 1'b1;
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
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;
if (PTP_TS_WIDTH == 96) begin
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
lanes_swapped <= 1'b1;
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;
detect_term <= {xgmii_term[3:0], swap_rxc_term};
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[95:48] <= ptp_ts[95:48];
end else begin
ptp_ts_reg <= ptp_ts + (((PTP_PERIOD_NS * 2**16 + PTP_PERIOD_FNS) * 3) >> 1);
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
if (reset_crc) begin