Rework MAC TX error handling to streamline logic; pad errored frames to avoid generating runt frames

Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
Alex Forencich 2024-01-29 18:33:14 -08:00
parent e24f887009
commit eb0f01f276
4 changed files with 203 additions and 287 deletions

View File

@ -171,8 +171,8 @@ localparam [2:0]
STATE_PAD = 3'd2, STATE_PAD = 3'd2,
STATE_FCS_1 = 3'd3, STATE_FCS_1 = 3'd3,
STATE_FCS_2 = 3'd4, STATE_FCS_2 = 3'd4,
STATE_IFG = 3'd5, STATE_ERR = 3'd5,
STATE_WAIT_END = 3'd6; STATE_IFG = 3'd6;
reg [2:0] state_reg = STATE_IDLE, state_next; reg [2:0] state_reg = STATE_IDLE, state_next;
@ -198,6 +198,8 @@ reg [3:0] fcs_output_type_1;
reg [7:0] ifg_offset; reg [7:0] ifg_offset;
reg frame_reg = 1'b0, frame_next;
reg frame_error_reg = 1'b0, frame_error_next;
reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next; reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next;
reg [7:0] ifg_count_reg = 8'd0, ifg_count_next; reg [7:0] ifg_count_reg = 8'd0, ifg_count_next;
@ -353,6 +355,8 @@ always @* begin
swap_lanes_next = swap_lanes_reg; swap_lanes_next = swap_lanes_reg;
frame_next = frame_reg;
frame_error_next = frame_error_reg;
frame_min_count_next = frame_min_count_reg; frame_min_count_next = frame_min_count_reg;
ifg_count_next = ifg_count_reg; ifg_count_next = ifg_count_reg;
@ -376,6 +380,10 @@ always @* begin
start_packet_next = 2'b00; start_packet_next = 2'b00;
error_underflow_next = 1'b0; error_underflow_next = 1'b0;
if (s_axis_tvalid && s_axis_tready) begin
frame_next = !s_axis_tlast;
end
if (PTP_TS_ENABLE && PTP_TS_WIDTH == 96) begin if (PTP_TS_ENABLE && PTP_TS_WIDTH == 96) begin
m_axis_ptp_ts_valid_next = m_axis_ptp_ts_valid_int_reg; m_axis_ptp_ts_valid_next = m_axis_ptp_ts_valid_int_reg;
m_axis_ptp_ts_adj_next[15:0] = m_axis_ptp_ts_reg[15:0]; m_axis_ptp_ts_adj_next[15:0] = m_axis_ptp_ts_reg[15:0];
@ -387,6 +395,7 @@ always @* begin
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_error_next = 1'b0;
frame_min_count_next = MIN_FRAME_LENGTH-4-KEEP_WIDTH; frame_min_count_next = MIN_FRAME_LENGTH-4-KEEP_WIDTH;
reset_crc = 1'b1; reset_crc = 1'b1;
s_axis_tready_next = 1'b1; s_axis_tready_next = 1'b1;
@ -467,15 +476,10 @@ always @* begin
s_tdata_next = s_axis_tdata_masked; s_tdata_next = s_axis_tdata_masked;
s_empty_next = keep2empty(s_axis_tkeep); s_empty_next = keep2empty(s_axis_tkeep);
if (s_axis_tvalid) begin if (!s_axis_tvalid || s_axis_tlast) begin
if (s_axis_tlast) begin s_axis_tready_next = frame_next; // drop frame
s_axis_tready_next = 1'b0; frame_error_next = !s_axis_tvalid || s_axis_tuser[0];
if (s_axis_tuser[0]) begin error_underflow_next = !s_axis_tvalid;
output_type_next = OUTPUT_TYPE_ERROR;
ifg_count_next = 8'd8;
state_next = STATE_IFG;
end else begin
s_axis_tready_next = 1'b0;
if (ENABLE_PADDING && frame_min_count_reg) begin if (ENABLE_PADDING && frame_min_count_reg) begin
if (frame_min_count_reg > KEEP_WIDTH) begin if (frame_min_count_reg > KEEP_WIDTH) begin
@ -485,8 +489,15 @@ always @* begin
if (keep2empty(s_axis_tkeep) > KEEP_WIDTH-frame_min_count_reg) begin if (keep2empty(s_axis_tkeep) > KEEP_WIDTH-frame_min_count_reg) begin
s_empty_next = KEEP_WIDTH-frame_min_count_reg; s_empty_next = KEEP_WIDTH-frame_min_count_reg;
end end
if (frame_error_next) begin
state_next = STATE_ERR;
end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
end
end else begin
if (frame_error_next) begin
state_next = STATE_ERR;
end else begin end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
@ -494,17 +505,10 @@ always @* begin
end else begin end else begin
state_next = STATE_PAYLOAD; state_next = STATE_PAYLOAD;
end end
end else begin
// tvalid deassert, fail frame
output_type_next = OUTPUT_TYPE_ERROR;
ifg_count_next = 8'd8;
error_underflow_next = 1'b1;
state_next = STATE_WAIT_END;
end
end end
STATE_PAD: begin STATE_PAD: begin
// pad frame to MIN_FRAME_LENGTH // pad frame to MIN_FRAME_LENGTH
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
output_data_next = s_tdata_reg; output_data_next = s_tdata_reg;
output_type_next = OUTPUT_TYPE_DATA; output_type_next = OUTPUT_TYPE_DATA;
@ -520,12 +524,16 @@ always @* begin
end else begin end else begin
frame_min_count_next = 0; frame_min_count_next = 0;
s_empty_next = KEEP_WIDTH-frame_min_count_reg; s_empty_next = KEEP_WIDTH-frame_min_count_reg;
if (frame_error_reg) begin
state_next = STATE_ERR;
end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
end end
end
STATE_FCS_1: begin STATE_FCS_1: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
output_data_next = fcs_output_data_0; output_data_next = fcs_output_data_0;
output_type_next = fcs_output_type_0; output_type_next = fcs_output_type_0;
@ -541,7 +549,7 @@ always @* begin
end end
STATE_FCS_2: begin STATE_FCS_2: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
output_data_next = fcs_output_data_1; output_data_next = fcs_output_data_1;
output_type_next = fcs_output_type_1; output_type_next = fcs_output_type_1;
@ -573,8 +581,24 @@ always @* begin
end end
end end
end end
STATE_ERR: begin
// terminate packet with error
s_axis_tready_next = frame_next; // drop frame
output_data_next = s_tdata_reg;
output_type_next = OUTPUT_TYPE_ERROR;
ifg_count_next = 8'd12;
state_next = STATE_IFG;
end
STATE_IFG: begin STATE_IFG: begin
// send IFG // send IFG
s_axis_tready_next = frame_next; // drop frame
output_data_next = s_tdata_reg;
output_type_next = OUTPUT_TYPE_IDLE;
if (ifg_count_reg > 8'd8) begin if (ifg_count_reg > 8'd8) begin
ifg_count_next = ifg_count_reg - 8'd8; ifg_count_next = ifg_count_reg - 8'd8;
end else begin end else begin
@ -584,7 +608,7 @@ always @* begin
reset_crc = 1'b1; reset_crc = 1'b1;
if (ENABLE_DIC) begin if (ENABLE_DIC) begin
if (ifg_count_next > 8'd7) begin if (ifg_count_next > 8'd7 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
if (ifg_count_next >= 8'd4) begin if (ifg_count_next >= 8'd4) begin
@ -599,7 +623,7 @@ always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
if (ifg_count_next > 8'd4) begin if (ifg_count_next > 8'd4 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
s_axis_tready_next = 1'b1; s_axis_tready_next = 1'b1;
@ -608,53 +632,6 @@ always @* begin
end end
end end
end end
STATE_WAIT_END: begin
// wait for end of frame
s_axis_tready_next = 1'b1;
if (ifg_count_reg > 8'd4) begin
ifg_count_next = ifg_count_reg - 8'd4;
end else begin
ifg_count_next = 8'd0;
end
reset_crc = 1'b1;
if (s_axis_tvalid) begin
if (s_axis_tlast) begin
s_axis_tready_next = 1'b0;
if (ENABLE_DIC) begin
if (ifg_count_next > 8'd7) begin
state_next = STATE_IFG;
end else begin
if (ifg_count_next >= 8'd4) begin
deficit_idle_count_next = ifg_count_next - 8'd4;
swap_lanes_next = 1'b1;
end else begin
deficit_idle_count_next = ifg_count_next;
ifg_count_next = 8'd0;
swap_lanes_next = 1'b0;
end
s_axis_tready_next = 1'b1;
state_next = STATE_IDLE;
end
end else begin
if (ifg_count_next > 8'd4) begin
state_next = STATE_IFG;
end else begin
s_axis_tready_next = 1'b1;
swap_lanes_next = ifg_count_next != 0;
state_next = STATE_IDLE;
end
end
end else begin
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WAIT_END;
end
end
endcase endcase
end end
@ -663,6 +640,8 @@ always @(posedge clk) begin
swap_lanes_reg <= swap_lanes_next; swap_lanes_reg <= swap_lanes_next;
frame_reg <= frame_next;
frame_error_reg <= frame_error_next;
frame_min_count_reg <= frame_min_count_next; frame_min_count_reg <= frame_min_count_next;
ifg_count_reg <= ifg_count_next; ifg_count_reg <= ifg_count_next;
@ -788,6 +767,8 @@ always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_reg <= 1'b0;
swap_lanes_reg <= 1'b0; swap_lanes_reg <= 1'b0;
ifg_count_reg <= 8'd0; ifg_count_reg <= 8'd0;

View File

@ -111,8 +111,7 @@ localparam [2:0]
STATE_LAST = 3'd3, STATE_LAST = 3'd3,
STATE_PAD = 3'd4, STATE_PAD = 3'd4,
STATE_FCS = 3'd5, STATE_FCS = 3'd5,
STATE_WAIT_END = 3'd6, STATE_IFG = 3'd6;
STATE_IFG = 3'd7;
reg [2:0] state_reg = STATE_IDLE, state_next; reg [2:0] state_reg = STATE_IDLE, state_next;
@ -125,6 +124,8 @@ reg [7:0] s_tdata_reg = 8'd0, s_tdata_next;
reg mii_odd_reg = 1'b0, mii_odd_next; reg mii_odd_reg = 1'b0, mii_odd_next;
reg [3:0] mii_msn_reg = 4'b0, mii_msn_next; reg [3:0] mii_msn_reg = 4'b0, mii_msn_next;
reg frame_reg = 1'b0, frame_next;
reg frame_error_reg = 1'b0, frame_error_next;
reg [7:0] frame_ptr_reg = 0, frame_ptr_next; reg [7:0] frame_ptr_reg = 0, frame_ptr_next;
reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next; reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next;
@ -183,6 +184,8 @@ always @* begin
mii_odd_next = mii_odd_reg; mii_odd_next = mii_odd_reg;
mii_msn_next = mii_msn_reg; mii_msn_next = mii_msn_reg;
frame_next = frame_reg;
frame_error_next = frame_error_reg;
frame_ptr_next = frame_ptr_reg; frame_ptr_next = frame_ptr_reg;
frame_min_count_next = frame_min_count_reg; frame_min_count_next = frame_min_count_reg;
@ -194,10 +197,6 @@ always @* begin
m_axis_ptp_ts_tag_next = m_axis_ptp_ts_tag_reg; m_axis_ptp_ts_tag_next = m_axis_ptp_ts_tag_reg;
m_axis_ptp_ts_valid_next = 1'b0; m_axis_ptp_ts_valid_next = 1'b0;
gmii_txd_next = {DATA_WIDTH{1'b0}};
gmii_tx_en_next = 1'b0;
gmii_tx_er_next = 1'b0;
if (start_packet_reg && PTP_TS_ENABLE) begin if (start_packet_reg && PTP_TS_ENABLE) begin
m_axis_ptp_ts_next = ptp_ts; m_axis_ptp_ts_next = ptp_ts;
if (PTP_TS_CTRL_IN_TUSER) begin if (PTP_TS_CTRL_IN_TUSER) begin
@ -209,10 +208,18 @@ always @* begin
end end
end end
gmii_txd_next = {DATA_WIDTH{1'b0}};
gmii_tx_en_next = 1'b0;
gmii_tx_er_next = 1'b0;
start_packet_int_next = start_packet_int_reg; start_packet_int_next = start_packet_int_reg;
start_packet_next = 1'b0; start_packet_next = 1'b0;
error_underflow_next = 1'b0; error_underflow_next = 1'b0;
if (s_axis_tvalid && s_axis_tready) begin
frame_next = !s_axis_tlast;
end
if (!clk_enable) begin if (!clk_enable) begin
// clock disabled - hold state and outputs // clock disabled - hold state and outputs
gmii_txd_next = gmii_txd_reg; gmii_txd_next = gmii_txd_reg;
@ -239,6 +246,7 @@ always @* begin
mii_odd_next = 1'b0; mii_odd_next = 1'b0;
frame_ptr_next = 1; frame_ptr_next = 1;
frame_error_next = 1'b0;
frame_min_count_next = MIN_FRAME_LENGTH-4-1; frame_min_count_next = MIN_FRAME_LENGTH-4-1;
if (s_axis_tvalid && cfg_tx_enable) begin if (s_axis_tvalid && cfg_tx_enable) begin
@ -299,29 +307,21 @@ always @* begin
s_tdata_next = s_axis_tdata; s_tdata_next = s_axis_tdata;
if (s_axis_tvalid) begin if (!s_axis_tvalid || s_axis_tlast) begin
if (s_axis_tlast) begin s_axis_tready_next = frame_next; // drop frame
s_axis_tready_next = !s_axis_tready_reg; frame_error_next = !s_axis_tvalid || s_axis_tuser[0];
if (s_axis_tuser[0]) begin error_underflow_next = !s_axis_tvalid;
gmii_tx_er_next = 1'b1;
state_next = STATE_IFG;
end else begin
state_next = STATE_LAST; state_next = STATE_LAST;
end
end else begin end else begin
state_next = STATE_PAYLOAD; state_next = STATE_PAYLOAD;
end end
end else begin
// tvalid deassert, fail frame
gmii_tx_er_next = 1'b1;
error_underflow_next = 1'b1;
state_next = STATE_WAIT_END;
end
end end
STATE_LAST: begin STATE_LAST: begin
// last payload word // last payload word
update_crc = 1'b1; update_crc = 1'b1;
s_axis_tready_next = 1'b0;
mii_odd_next = 1'b1; mii_odd_next = 1'b1;
@ -339,6 +339,7 @@ always @* begin
end end
STATE_PAD: begin STATE_PAD: begin
// send padding // send padding
s_axis_tready_next = frame_next; // drop frame
update_crc = 1'b1; update_crc = 1'b1;
mii_odd_next = 1'b1; mii_odd_next = 1'b1;
@ -358,6 +359,7 @@ always @* begin
end end
STATE_FCS: begin STATE_FCS: begin
// send FCS // send FCS
s_axis_tready_next = frame_next; // drop frame
mii_odd_next = 1'b1; mii_odd_next = 1'b1;
frame_ptr_next = frame_ptr_reg + 1; frame_ptr_next = frame_ptr_reg + 1;
@ -369,6 +371,7 @@ always @* begin
2'd3: gmii_txd_next = ~crc_state[31:24]; 2'd3: gmii_txd_next = ~crc_state[31:24];
endcase endcase
gmii_tx_en_next = 1'b1; gmii_tx_en_next = 1'b1;
gmii_tx_er_next = frame_error_reg;
if (frame_ptr_reg < 3) begin if (frame_ptr_reg < 3) begin
state_next = STATE_FCS; state_next = STATE_FCS;
@ -377,35 +380,14 @@ always @* begin
state_next = STATE_IFG; state_next = STATE_IFG;
end end
end end
STATE_WAIT_END: begin
// wait for end of frame
mii_odd_next = 1'b1;
frame_ptr_next = frame_ptr_reg + 1;
s_axis_tready_next = 1'b1;
if (s_axis_tvalid) begin
if (s_axis_tlast) begin
s_axis_tready_next = !s_axis_tready_reg;
if (frame_ptr_reg < cfg_ifg-1) begin
state_next = STATE_IFG;
end else begin
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WAIT_END;
end
end
STATE_IFG: begin STATE_IFG: begin
// send IFG // send IFG
s_axis_tready_next = frame_next; // drop frame
mii_odd_next = 1'b1; mii_odd_next = 1'b1;
frame_ptr_next = frame_ptr_reg + 1; frame_ptr_next = frame_ptr_reg + 1;
if (frame_ptr_reg < cfg_ifg-1) begin if (frame_ptr_reg < cfg_ifg-1 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
@ -423,6 +405,8 @@ end
always @(posedge clk) begin always @(posedge clk) begin
state_reg <= state_next; state_reg <= state_next;
frame_reg <= frame_next;
frame_error_reg <= frame_error_next;
frame_ptr_reg <= frame_ptr_next; frame_ptr_reg <= frame_ptr_next;
frame_min_count_reg <= frame_min_count_next; frame_min_count_reg <= frame_min_count_next;
@ -454,6 +438,8 @@ always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_reg <= 1'b0;
s_axis_tready_reg <= 1'b0; s_axis_tready_reg <= 1'b0;
m_axis_ptp_ts_valid_reg <= 1'b0; m_axis_ptp_ts_valid_reg <= 1'b0;

View File

@ -121,8 +121,8 @@ localparam [3:0]
STATE_FCS_1 = 4'd4, STATE_FCS_1 = 4'd4,
STATE_FCS_2 = 4'd5, STATE_FCS_2 = 4'd5,
STATE_FCS_3 = 4'd6, STATE_FCS_3 = 4'd6,
STATE_IFG = 4'd7, STATE_ERR = 4'd7,
STATE_WAIT_END = 4'd8; STATE_IFG = 4'd8;
reg [3:0] state_reg = STATE_IDLE, state_next; reg [3:0] state_reg = STATE_IDLE, state_next;
@ -144,6 +144,8 @@ reg [7:0] ifg_offset;
reg extra_cycle; reg extra_cycle;
reg frame_reg = 1'b0, frame_next;
reg frame_error_reg = 1'b0, frame_error_next;
reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next; reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next;
reg [7:0] ifg_count_reg = 8'd0, ifg_count_next; reg [7:0] ifg_count_reg = 8'd0, ifg_count_next;
@ -263,6 +265,8 @@ always @* begin
reset_crc = 1'b0; reset_crc = 1'b0;
update_crc = 1'b0; update_crc = 1'b0;
frame_next = frame_reg;
frame_error_next = frame_error_reg;
frame_min_count_next = frame_min_count_reg; frame_min_count_next = frame_min_count_reg;
ifg_count_next = ifg_count_reg; ifg_count_next = ifg_count_reg;
@ -295,9 +299,14 @@ always @* begin
start_packet_next = 1'b0; start_packet_next = 1'b0;
error_underflow_next = 1'b0; error_underflow_next = 1'b0;
if (s_axis_tvalid && s_axis_tready) begin
frame_next = !s_axis_tlast;
end
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_error_next = 1'b0;
frame_min_count_next = MIN_FRAME_LENGTH-4-CTRL_WIDTH; frame_min_count_next = MIN_FRAME_LENGTH-4-CTRL_WIDTH;
reset_crc = 1'b1; reset_crc = 1'b1;
@ -351,16 +360,10 @@ always @* begin
s_tdata_next = s_axis_tdata_masked; s_tdata_next = s_axis_tdata_masked;
s_empty_next = keep2empty(s_axis_tkeep); s_empty_next = keep2empty(s_axis_tkeep);
if (s_axis_tvalid) begin if (!s_axis_tvalid || s_axis_tlast) begin
if (s_axis_tlast) begin s_axis_tready_next = frame_next; // drop frame
s_axis_tready_next = 1'b0; frame_error_next = !s_axis_tvalid || s_axis_tuser[0];
if (s_axis_tuser[0]) begin error_underflow_next = !s_axis_tvalid;
xgmii_txd_next = {XGMII_TERM, {3{XGMII_ERROR}}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
ifg_count_next = 8'd10;
state_next = STATE_IFG;
end else begin
s_axis_tready_next = 1'b0;
if (ENABLE_PADDING && frame_min_count_reg) begin if (ENABLE_PADDING && frame_min_count_reg) begin
if (frame_min_count_reg > CTRL_WIDTH) begin if (frame_min_count_reg > CTRL_WIDTH) begin
@ -375,22 +378,13 @@ always @* begin
end else begin end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
end
end else begin end else begin
state_next = STATE_PAYLOAD; state_next = STATE_PAYLOAD;
end end
end else begin
// tvalid deassert, fail frame
xgmii_txd_next = {XGMII_TERM, {3{XGMII_ERROR}}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
ifg_count_next = 8'd10;
error_underflow_next = 1'b1;
state_next = STATE_WAIT_END;
end
end end
STATE_PAD: begin STATE_PAD: begin
// pad frame to MIN_FRAME_LENGTH // pad frame to MIN_FRAME_LENGTH
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = s_tdata_reg; xgmii_txd_next = s_tdata_reg;
xgmii_txc_next = {CTRL_WIDTH{1'b0}}; xgmii_txc_next = {CTRL_WIDTH{1'b0}};
@ -411,7 +405,7 @@ always @* begin
end end
STATE_FCS_1: begin STATE_FCS_1: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = fcs_output_txd_0; xgmii_txd_next = fcs_output_txd_0;
xgmii_txc_next = fcs_output_txc_0; xgmii_txc_next = fcs_output_txc_0;
@ -419,11 +413,15 @@ always @* begin
update_crc = 1'b1; update_crc = 1'b1;
ifg_count_next = (cfg_ifg > 8'd12 ? cfg_ifg : 8'd12) - ifg_offset + deficit_idle_count_reg; ifg_count_next = (cfg_ifg > 8'd12 ? cfg_ifg : 8'd12) - ifg_offset + deficit_idle_count_reg;
if (frame_error_reg) begin
state_next = STATE_ERR;
end else begin
state_next = STATE_FCS_2; state_next = STATE_FCS_2;
end end
end
STATE_FCS_2: begin STATE_FCS_2: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = fcs_output_txd_1; xgmii_txd_next = fcs_output_txd_1;
xgmii_txc_next = fcs_output_txc_1; xgmii_txc_next = fcs_output_txc_1;
@ -436,7 +434,7 @@ always @* begin
end end
STATE_FCS_3: begin STATE_FCS_3: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = {{3{XGMII_IDLE}}, XGMII_TERM}; xgmii_txd_next = {{3{XGMII_IDLE}}, XGMII_TERM};
xgmii_txc_next = {CTRL_WIDTH{1'b1}}; xgmii_txc_next = {CTRL_WIDTH{1'b1}};
@ -458,8 +456,21 @@ always @* begin
end end
end end
end end
STATE_ERR: begin
// terminate packet with error
s_axis_tready_next = frame_next; // drop frame
// XGMII error
xgmii_txd_next = {XGMII_TERM, {3{XGMII_ERROR}}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
ifg_count_next = 8'd12;
state_next = STATE_IFG;
end
STATE_IFG: begin STATE_IFG: begin
// send IFG // send IFG
s_axis_tready_next = frame_next; // drop frame
// XGMII idle // XGMII idle
xgmii_txd_next = {CTRL_WIDTH{XGMII_IDLE}}; xgmii_txd_next = {CTRL_WIDTH{XGMII_IDLE}};
@ -472,7 +483,7 @@ always @* begin
end end
if (ENABLE_DIC) begin if (ENABLE_DIC) begin
if (ifg_count_next > 8'd3) begin if (ifg_count_next > 8'd3 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
deficit_idle_count_next = ifg_count_next; deficit_idle_count_next = ifg_count_next;
@ -480,59 +491,21 @@ always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
if (ifg_count_next > 8'd0) begin if (ifg_count_next > 8'd0 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end end
end end
STATE_WAIT_END: begin
// wait for end of frame
s_axis_tready_next = 1'b1;
// XGMII idle
xgmii_txd_next = {CTRL_WIDTH{XGMII_IDLE}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
if (ifg_count_reg > 8'd4) begin
ifg_count_next = ifg_count_reg - 8'd4;
end else begin
ifg_count_next = 8'd0;
end
if (s_axis_tvalid) begin
if (s_axis_tlast) begin
s_axis_tready_next = 1'b0;
if (ENABLE_DIC) begin
if (ifg_count_next > 8'd3) begin
state_next = STATE_IFG;
end else begin
deficit_idle_count_next = ifg_count_next;
ifg_count_next = 8'd0;
state_next = STATE_IDLE;
end
end else begin
if (ifg_count_next > 8'd0) begin
state_next = STATE_IFG;
end else begin
state_next = STATE_IDLE;
end
end
end else begin
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WAIT_END;
end
end
endcase endcase
end end
always @(posedge clk) begin always @(posedge clk) begin
state_reg <= state_next; state_reg <= state_next;
frame_reg <= frame_next;
frame_error_reg <= frame_error_next;
frame_min_count_reg <= frame_min_count_next; frame_min_count_reg <= frame_min_count_next;
ifg_count_reg <= ifg_count_next; ifg_count_reg <= ifg_count_next;
@ -568,6 +541,8 @@ always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_reg <= 1'b0;
ifg_count_reg <= 8'd0; ifg_count_reg <= 8'd0;
deficit_idle_count_reg <= 2'd0; deficit_idle_count_reg <= 2'd0;

View File

@ -121,8 +121,8 @@ localparam [2:0]
STATE_PAD = 3'd2, STATE_PAD = 3'd2,
STATE_FCS_1 = 3'd3, STATE_FCS_1 = 3'd3,
STATE_FCS_2 = 3'd4, STATE_FCS_2 = 3'd4,
STATE_IFG = 3'd5, STATE_ERR = 3'd5,
STATE_WAIT_END = 3'd6; STATE_IFG = 3'd6;
reg [2:0] state_reg = STATE_IDLE, state_next; reg [2:0] state_reg = STATE_IDLE, state_next;
@ -146,6 +146,8 @@ reg [CTRL_WIDTH-1:0] fcs_output_txc_1;
reg [7:0] ifg_offset; reg [7:0] ifg_offset;
reg frame_reg = 1'b0, frame_next;
reg frame_error_reg = 1'b0, frame_error_next;
reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next; reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next;
reg [7:0] ifg_count_reg = 8'd0, ifg_count_next; reg [7:0] ifg_count_reg = 8'd0, ifg_count_next;
@ -298,6 +300,8 @@ always @* begin
swap_lanes_next = swap_lanes_reg; swap_lanes_next = swap_lanes_reg;
frame_next = frame_reg;
frame_error_next = frame_error_reg;
frame_min_count_next = frame_min_count_reg; frame_min_count_next = frame_min_count_reg;
ifg_count_next = ifg_count_reg; ifg_count_next = ifg_count_reg;
@ -322,6 +326,10 @@ always @* begin
start_packet_next = 2'b00; start_packet_next = 2'b00;
error_underflow_next = 1'b0; error_underflow_next = 1'b0;
if (s_axis_tvalid && s_axis_tready) begin
frame_next = !s_axis_tlast;
end
if (PTP_TS_ENABLE && PTP_TS_WIDTH == 96) begin if (PTP_TS_ENABLE && PTP_TS_WIDTH == 96) begin
m_axis_ptp_ts_valid_next = m_axis_ptp_ts_valid_int_reg; m_axis_ptp_ts_valid_next = m_axis_ptp_ts_valid_int_reg;
m_axis_ptp_ts_adj_next[15:0] = m_axis_ptp_ts_reg[15:0]; m_axis_ptp_ts_adj_next[15:0] = m_axis_ptp_ts_reg[15:0];
@ -333,6 +341,7 @@ always @* begin
case (state_reg) case (state_reg)
STATE_IDLE: begin STATE_IDLE: begin
// idle state - wait for data // idle state - wait for data
frame_error_next = 1'b0;
frame_min_count_next = MIN_FRAME_LENGTH-4-CTRL_WIDTH; frame_min_count_next = MIN_FRAME_LENGTH-4-CTRL_WIDTH;
reset_crc = 1'b1; reset_crc = 1'b1;
s_axis_tready_next = cfg_tx_enable; s_axis_tready_next = cfg_tx_enable;
@ -414,16 +423,10 @@ always @* begin
s_tdata_next = s_axis_tdata_masked; s_tdata_next = s_axis_tdata_masked;
s_empty_next = keep2empty(s_axis_tkeep); s_empty_next = keep2empty(s_axis_tkeep);
if (s_axis_tvalid) begin if (!s_axis_tvalid || s_axis_tlast) begin
if (s_axis_tlast) begin s_axis_tready_next = frame_next; // drop frame
s_axis_tready_next = 1'b0; frame_error_next = !s_axis_tvalid || s_axis_tuser[0];
if (s_axis_tuser[0]) begin error_underflow_next = !s_axis_tvalid;
xgmii_txd_next = {{3{XGMII_IDLE}}, XGMII_TERM, {4{XGMII_ERROR}}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
ifg_count_next = 8'd8;
state_next = STATE_IFG;
end else begin
s_axis_tready_next = 1'b0;
if (ENABLE_PADDING && frame_min_count_reg) begin if (ENABLE_PADDING && frame_min_count_reg) begin
if (frame_min_count_reg > CTRL_WIDTH) begin if (frame_min_count_reg > CTRL_WIDTH) begin
@ -433,8 +436,15 @@ always @* begin
if (keep2empty(s_axis_tkeep) > CTRL_WIDTH-frame_min_count_reg) begin if (keep2empty(s_axis_tkeep) > CTRL_WIDTH-frame_min_count_reg) begin
s_empty_next = CTRL_WIDTH-frame_min_count_reg; s_empty_next = CTRL_WIDTH-frame_min_count_reg;
end end
if (frame_error_next) begin
state_next = STATE_ERR;
end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
end
end else begin
if (frame_error_next) begin
state_next = STATE_ERR;
end else begin end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
@ -442,18 +452,10 @@ always @* begin
end else begin end else begin
state_next = STATE_PAYLOAD; state_next = STATE_PAYLOAD;
end end
end else begin
// tvalid deassert, fail frame
xgmii_txd_next = {{3{XGMII_IDLE}}, XGMII_TERM, {4{XGMII_ERROR}}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
ifg_count_next = 8'd8;
error_underflow_next = 1'b1;
state_next = STATE_WAIT_END;
end
end end
STATE_PAD: begin STATE_PAD: begin
// pad frame to MIN_FRAME_LENGTH // pad frame to MIN_FRAME_LENGTH
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = s_tdata_reg; xgmii_txd_next = s_tdata_reg;
xgmii_txc_next = {CTRL_WIDTH{1'b0}}; xgmii_txc_next = {CTRL_WIDTH{1'b0}};
@ -469,12 +471,16 @@ always @* begin
end else begin end else begin
frame_min_count_next = 0; frame_min_count_next = 0;
s_empty_next = CTRL_WIDTH-frame_min_count_reg; s_empty_next = CTRL_WIDTH-frame_min_count_reg;
if (frame_error_reg) begin
state_next = STATE_ERR;
end else begin
state_next = STATE_FCS_1; state_next = STATE_FCS_1;
end end
end end
end
STATE_FCS_1: begin STATE_FCS_1: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = fcs_output_txd_0; xgmii_txd_next = fcs_output_txd_0;
xgmii_txc_next = fcs_output_txc_0; xgmii_txc_next = fcs_output_txc_0;
@ -490,7 +496,7 @@ always @* begin
end end
STATE_FCS_2: begin STATE_FCS_2: begin
// last cycle // last cycle
s_axis_tready_next = 1'b0; s_axis_tready_next = frame_next; // drop frame
xgmii_txd_next = fcs_output_txd_1; xgmii_txd_next = fcs_output_txd_1;
xgmii_txc_next = fcs_output_txc_1; xgmii_txc_next = fcs_output_txc_1;
@ -520,8 +526,21 @@ always @* begin
end end
end end
end end
STATE_ERR: begin
// terminate packet with error
s_axis_tready_next = frame_next; // drop frame
// XGMII error
xgmii_txd_next = {XGMII_TERM, {7{XGMII_ERROR}}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
ifg_count_next = 8'd12;
state_next = STATE_IFG;
end
STATE_IFG: begin STATE_IFG: begin
// send IFG // send IFG
s_axis_tready_next = frame_next; // drop frame
// XGMII idle // XGMII idle
xgmii_txd_next = {CTRL_WIDTH{XGMII_IDLE}}; xgmii_txd_next = {CTRL_WIDTH{XGMII_IDLE}};
@ -534,7 +553,7 @@ always @* begin
end end
if (ENABLE_DIC) begin if (ENABLE_DIC) begin
if (ifg_count_next > 8'd7) begin if (ifg_count_next > 8'd7 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
if (ifg_count_next >= 8'd4) begin if (ifg_count_next >= 8'd4) begin
@ -549,7 +568,7 @@ always @* begin
state_next = STATE_IDLE; state_next = STATE_IDLE;
end end
end else begin end else begin
if (ifg_count_next > 8'd4) begin if (ifg_count_next > 8'd4 || frame_reg) begin
state_next = STATE_IFG; state_next = STATE_IFG;
end else begin end else begin
s_axis_tready_next = cfg_tx_enable; s_axis_tready_next = cfg_tx_enable;
@ -558,55 +577,6 @@ always @* begin
end end
end end
end end
STATE_WAIT_END: begin
// wait for end of frame
s_axis_tready_next = 1'b1;
// XGMII idle
xgmii_txd_next = {CTRL_WIDTH{XGMII_IDLE}};
xgmii_txc_next = {CTRL_WIDTH{1'b1}};
if (ifg_count_reg > 8'd8) begin
ifg_count_next = ifg_count_reg - 8'd8;
end else begin
ifg_count_next = 8'd0;
end
if (s_axis_tvalid) begin
if (s_axis_tlast) begin
s_axis_tready_next = 1'b0;
if (ENABLE_DIC) begin
if (ifg_count_next > 8'd7) begin
state_next = STATE_IFG;
end else begin
if (ifg_count_next >= 8'd4) begin
deficit_idle_count_next = ifg_count_next - 8'd4;
swap_lanes_next = 1'b1;
end else begin
deficit_idle_count_next = ifg_count_next;
ifg_count_next = 8'd0;
swap_lanes_next = 1'b0;
end
s_axis_tready_next = cfg_tx_enable;
state_next = STATE_IDLE;
end
end else begin
if (ifg_count_next > 8'd4) begin
state_next = STATE_IFG;
end else begin
s_axis_tready_next = cfg_tx_enable;
swap_lanes_next = ifg_count_next != 0;
state_next = STATE_IDLE;
end
end
end else begin
state_next = STATE_WAIT_END;
end
end else begin
state_next = STATE_WAIT_END;
end
end
endcase endcase
end end
@ -615,6 +585,8 @@ always @(posedge clk) begin
swap_lanes_reg <= swap_lanes_next; swap_lanes_reg <= swap_lanes_next;
frame_reg <= frame_next;
frame_error_reg <= frame_error_next;
frame_min_count_reg <= frame_min_count_next; frame_min_count_reg <= frame_min_count_next;
ifg_count_reg <= ifg_count_next; ifg_count_reg <= ifg_count_next;
@ -665,6 +637,8 @@ always @(posedge clk) begin
if (rst) begin if (rst) begin
state_reg <= STATE_IDLE; state_reg <= STATE_IDLE;
frame_reg <= 1'b0;
swap_lanes_reg <= 1'b0; swap_lanes_reg <= 1'b0;
ifg_count_reg <= 8'd0; ifg_count_reg <= 8'd0;