mirror of
https://github.com/alexforencich/verilog-ethernet.git
synced 2025-01-28 07:03:08 +08:00
Rework termination character handling in XGMII RX modules
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
parent
12744433de
commit
f37bb1fc8d
@ -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;
|
||||
|
@ -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
|
||||
lanes_swapped <= 1'b0;
|
||||
start_packet_reg <= 2'b01;
|
||||
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;
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user