diff --git a/rtl/eth/taxi_axis_baser_rx_64.sv b/rtl/eth/taxi_axis_baser_rx_64.sv index e53a14a..1d96de0 100644 --- a/rtl/eth/taxi_axis_baser_rx_64.sv +++ b/rtl/eth/taxi_axis_baser_rx_64.sv @@ -46,18 +46,31 @@ module taxi_axis_baser_rx_64 # /* * Configuration */ + input wire logic [15:0] cfg_rx_max_pkt_len = 16'd1518, input wire logic cfg_rx_enable, /* * Status */ - output wire logic [1:0] start_packet, - output wire logic error_bad_frame, - output wire logic error_bad_fcs, - output wire logic rx_bad_block, - output wire logic rx_sequence_error + output wire logic [1:0] rx_start_packet, + output wire logic [3:0] stat_rx_byte, + output wire logic [15:0] stat_rx_pkt_len, + output wire logic stat_rx_pkt_fragment, + output wire logic stat_rx_pkt_jabber, + output wire logic stat_rx_pkt_ucast, + output wire logic stat_rx_pkt_mcast, + output wire logic stat_rx_pkt_bcast, + output wire logic stat_rx_pkt_vlan, + output wire logic stat_rx_pkt_good, + output wire logic stat_rx_pkt_bad, + output wire logic stat_rx_err_oversize, + output wire logic stat_rx_err_bad_fcs, + output wire logic stat_rx_err_bad_block, + output wire logic stat_rx_err_framing, + output wire logic stat_rx_err_preamble ); +// extract parameters localparam KEEP_W = DATA_W/8; localparam USER_W = (PTP_TS_EN ? PTP_TS_W : 0) + 1; @@ -164,6 +177,15 @@ logic input_start_swap = 1'b0; logic input_start_d0 = 1'b0; logic input_start_d1 = 1'b0; +logic frame_oversize_reg = 1'b0, frame_oversize_next; +logic pre_ok_reg = 1'b0, pre_ok_next; +logic [0:0] hdr_ptr_reg = '0, hdr_ptr_next; +logic is_mcast_reg = 1'b0, is_mcast_next; +logic is_bcast_reg = 1'b0, is_bcast_next; +logic is_8021q_reg = 1'b0, is_8021q_next; +logic [15:0] frame_len_reg = '0, frame_len_next; +logic [15:0] frame_len_lim_reg = '0, frame_len_lim_next; + logic [DATA_W-1:0] m_axis_rx_tdata_reg = '0, m_axis_rx_tdata_next; logic [KEEP_W-1:0] m_axis_rx_tkeep_reg = '0, m_axis_rx_tkeep_next; logic m_axis_rx_tvalid_reg = 1'b0, m_axis_rx_tvalid_next; @@ -171,12 +193,24 @@ logic m_axis_rx_tlast_reg = 1'b0, m_axis_rx_tlast_next; logic m_axis_rx_tuser_reg = 1'b0, m_axis_rx_tuser_next; logic [1:0] start_packet_reg = 2'b00; -logic error_bad_frame_reg = 1'b0, error_bad_frame_next; -logic error_bad_fcs_reg = 1'b0, error_bad_fcs_next; -logic rx_bad_block_reg = 1'b0; -logic rx_sequence_error_reg = 1'b0; logic frame_reg = 1'b0; +logic [3:0] stat_rx_byte_reg = '0, stat_rx_byte_next; +logic [15:0] stat_rx_pkt_len_reg = '0, stat_rx_pkt_len_next; +logic stat_rx_pkt_fragment_reg = 1'b0, stat_rx_pkt_fragment_next; +logic stat_rx_pkt_jabber_reg = 1'b0, stat_rx_pkt_jabber_next; +logic stat_rx_pkt_ucast_reg = 1'b0, stat_rx_pkt_ucast_next; +logic stat_rx_pkt_mcast_reg = 1'b0, stat_rx_pkt_mcast_next; +logic stat_rx_pkt_bcast_reg = 1'b0, stat_rx_pkt_bcast_next; +logic stat_rx_pkt_vlan_reg = 1'b0, stat_rx_pkt_vlan_next; +logic stat_rx_pkt_good_reg = 1'b0, stat_rx_pkt_good_next; +logic stat_rx_pkt_bad_reg = 1'b0, stat_rx_pkt_bad_next; +logic stat_rx_err_oversize_reg = 1'b0, stat_rx_err_oversize_next; +logic stat_rx_err_bad_fcs_reg = 1'b0, stat_rx_err_bad_fcs_next; +logic stat_rx_err_bad_block_reg = 1'b0; +logic stat_rx_err_framing_reg = 1'b0; +logic stat_rx_err_preamble_reg = 1'b0, stat_rx_err_preamble_next; + logic [PTP_TS_W-1:0] ptp_ts_reg = '0; logic [PTP_TS_W-1:0] ptp_ts_out_reg = '0, ptp_ts_out_next; logic [PTP_TS_W-1:0] ptp_ts_adj_reg = '0; @@ -213,11 +247,23 @@ if (PTP_TS_EN) begin assign m_axis_rx.tuser[1 +: PTP_TS_W] = ptp_ts_out_reg; end -assign start_packet = start_packet_reg; -assign error_bad_frame = error_bad_frame_reg; -assign error_bad_fcs = error_bad_fcs_reg; -assign rx_bad_block = rx_bad_block_reg; -assign rx_sequence_error = rx_sequence_error_reg; +assign rx_start_packet = start_packet_reg; + +assign stat_rx_byte = stat_rx_byte_reg; +assign stat_rx_pkt_len = stat_rx_pkt_len_reg; +assign stat_rx_pkt_fragment = stat_rx_pkt_fragment_reg; +assign stat_rx_pkt_jabber = stat_rx_pkt_jabber_reg; +assign stat_rx_pkt_ucast = stat_rx_pkt_ucast_reg; +assign stat_rx_pkt_mcast = stat_rx_pkt_mcast_reg; +assign stat_rx_pkt_bcast = stat_rx_pkt_bcast_reg; +assign stat_rx_pkt_vlan = stat_rx_pkt_vlan_reg; +assign stat_rx_pkt_good = stat_rx_pkt_good_reg; +assign stat_rx_pkt_bad = stat_rx_pkt_bad_reg; +assign stat_rx_err_oversize = stat_rx_err_oversize_reg; +assign stat_rx_err_bad_fcs = stat_rx_err_bad_fcs_reg; +assign stat_rx_err_bad_block = stat_rx_err_bad_block_reg; +assign stat_rx_err_framing = stat_rx_err_framing_reg; +assign stat_rx_err_preamble = stat_rx_err_preamble_reg; taxi_lfsr #( .LFSR_W(32), @@ -266,6 +312,15 @@ always_comb begin reset_crc = 1'b0; + frame_oversize_next = frame_oversize_reg; + pre_ok_next = pre_ok_reg; + hdr_ptr_next = hdr_ptr_reg; + is_mcast_next = is_mcast_reg; + is_bcast_next = is_bcast_reg; + is_8021q_next = is_8021q_reg; + frame_len_next = frame_len_reg; + frame_len_lim_next = frame_len_lim_reg; + m_axis_rx_tdata_next = input_data_d1; m_axis_rx_tkeep_next = 8'd0; m_axis_rx_tvalid_next = 1'b0; @@ -275,17 +330,69 @@ always_comb begin ptp_ts_out_next = ptp_ts_out_reg; - error_bad_frame_next = 1'b0; - error_bad_fcs_next = 1'b0; + stat_rx_byte_next = '0; + stat_rx_pkt_len_next = '0; + stat_rx_pkt_fragment_next = 1'b0; + stat_rx_pkt_jabber_next = 1'b0; + stat_rx_pkt_ucast_next = 1'b0; + stat_rx_pkt_mcast_next = 1'b0; + stat_rx_pkt_bcast_next = 1'b0; + stat_rx_pkt_vlan_next = 1'b0; + stat_rx_pkt_good_next = 1'b0; + stat_rx_pkt_bad_next = 1'b0; + stat_rx_err_oversize_next = 1'b0; + stat_rx_err_bad_fcs_next = 1'b0; + stat_rx_err_preamble_next = 1'b0; + + // counter to measure frame length + if (&frame_len_reg[15:3] == 0) begin + if (input_type_d0[3]) begin + frame_len_next = frame_len_reg + 16'(input_type_d0[2:0]); + end else begin + frame_len_next = frame_len_reg + 16'(KEEP_W); + end + end else begin + frame_len_next = '1; + end + + // counter for max frame length enforcement + if (frame_len_lim_reg[15:3] != 0) begin + frame_len_lim_next = frame_len_lim_reg - 16'(KEEP_W); + end else begin + frame_len_lim_next = '0; + end + + // address and ethertype checks + if (&hdr_ptr_reg == 0) begin + hdr_ptr_next = hdr_ptr_reg + 1; + end + + case (hdr_ptr_reg) + 1'd0: begin + is_mcast_next = input_data_d1[0]; + is_bcast_next = &input_data_d1[47:0]; + end + 1'd1: is_8021q_next = {input_data_d1[39:32], input_data_d1[47:40]} == 16'h8100; + default: begin + // do nothing + end + endcase case (state_reg) STATE_IDLE: begin // idle state - wait for packet reset_crc = 1'b1; + frame_len_next = 16'(KEEP_W); + frame_len_lim_next = cfg_rx_max_pkt_len; + hdr_ptr_next = 0; + + pre_ok_next = input_data_d1[63:8] == 56'hD5555555555555; + if (input_start_d1 && cfg_rx_enable) begin // start condition reset_crc = 1'b0; + stat_rx_byte_next = 4'(KEEP_W); state_next = STATE_PAYLOAD; end else begin state_next = STATE_IDLE; @@ -299,6 +406,14 @@ always_comb begin m_axis_rx_tlast_next = 1'b0; m_axis_rx_tuser_next = 1'b0; + if (input_type_d0[3]) begin + stat_rx_byte_next = 4'(input_type_d0[2:0]); + frame_oversize_next = frame_len_lim_reg < 16'(8+input_type_d0[2:0]); + end else begin + stat_rx_byte_next = 4'(KEEP_W); + frame_oversize_next = frame_len_lim_reg < 8; + end + if (input_type_d0[3]) begin // INPUT_TYPE_TERM_* reset_crc = 1'b1; @@ -329,11 +444,31 @@ always_comb begin (input_type_d0 == INPUT_TYPE_TERM_3 && crc_valid[2]) || (input_type_d0 == INPUT_TYPE_TERM_4 && crc_valid[3])) begin // CRC valid + if (frame_oversize_next) begin + // too long + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_bad_next = 1'b1; + end else begin + // length OK + m_axis_rx_tuser_next = 1'b0; + stat_rx_pkt_good_next = 1'b1; + end end else begin m_axis_rx_tuser_next = 1'b1; - error_bad_frame_next = 1'b1; - error_bad_fcs_next = 1'b1; + stat_rx_pkt_fragment_next = frame_len_next[15:6] == 0; + stat_rx_pkt_jabber_next = frame_oversize_next; + stat_rx_pkt_bad_next = 1'b1; + stat_rx_err_bad_fcs_next = 1'b1; end + + stat_rx_pkt_len_next = frame_len_next; + stat_rx_pkt_ucast_next = !is_mcast_reg; + stat_rx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; + stat_rx_pkt_bcast_next = is_bcast_reg; + stat_rx_pkt_vlan_next = is_8021q_reg; + stat_rx_err_oversize_next = frame_oversize_next; + stat_rx_err_preamble_next = !pre_ok_reg; + state_next = STATE_IDLE; end else begin // need extra cycle @@ -343,7 +478,18 @@ always_comb begin // control or error characters in packet m_axis_rx_tlast_next = 1'b1; m_axis_rx_tuser_next = 1'b1; - error_bad_frame_next = 1'b1; + stat_rx_pkt_bad_next = 1'b1; + + stat_rx_pkt_len_next = frame_len_next; + stat_rx_pkt_ucast_next = !is_mcast_reg; + stat_rx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; + stat_rx_pkt_bcast_next = is_bcast_reg; + stat_rx_pkt_vlan_next = is_8021q_reg; + stat_rx_err_oversize_next = frame_oversize_next; + stat_rx_err_preamble_next = !pre_ok_reg; + stat_rx_pkt_fragment_next = frame_len_next[15:6] == 0; + stat_rx_pkt_jabber_next = frame_oversize_next; + reset_crc = 1'b1; state_next = STATE_IDLE; end @@ -369,12 +515,31 @@ always_comb begin (input_type_d1 == INPUT_TYPE_TERM_6 && crc_valid_save[5]) || (input_type_d1 == INPUT_TYPE_TERM_7 && crc_valid_save[6])) begin // CRC valid + if (frame_oversize_reg) begin + // too long + m_axis_rx_tuser_next = 1'b1; + stat_rx_pkt_bad_next = 1'b1; + end else begin + // length OK + m_axis_rx_tuser_next = 1'b0; + stat_rx_pkt_good_next = 1'b1; + end end else begin m_axis_rx_tuser_next = 1'b1; - error_bad_frame_next = 1'b1; - error_bad_fcs_next = 1'b1; + stat_rx_pkt_fragment_next = frame_len_reg[15:6] == 0; + stat_rx_pkt_jabber_next = frame_oversize_reg; + stat_rx_pkt_bad_next = 1'b1; + stat_rx_err_bad_fcs_next = 1'b1; end + stat_rx_pkt_len_next = frame_len_reg; + stat_rx_pkt_ucast_next = !is_mcast_reg; + stat_rx_pkt_mcast_next = is_mcast_reg && !is_bcast_reg; + stat_rx_pkt_bcast_next = is_bcast_reg; + stat_rx_pkt_vlan_next = is_8021q_reg; + stat_rx_err_oversize_next = frame_oversize_reg; + stat_rx_err_preamble_next = !pre_ok_reg; + state_next = STATE_IDLE; end default: begin @@ -387,6 +552,15 @@ end always_ff @(posedge clk) begin state_reg <= state_next; + frame_oversize_reg <= frame_oversize_next; + pre_ok_reg <= pre_ok_next; + hdr_ptr_reg <= hdr_ptr_next; + is_mcast_reg <= is_mcast_next; + is_bcast_reg <= is_bcast_next; + is_8021q_reg <= is_8021q_next; + frame_len_reg <= frame_len_next; + frame_len_lim_reg <= frame_len_lim_next; + m_axis_rx_tdata_reg <= m_axis_rx_tdata_next; m_axis_rx_tkeep_reg <= m_axis_rx_tkeep_next; m_axis_rx_tvalid_reg <= m_axis_rx_tvalid_next; @@ -396,10 +570,22 @@ always_ff @(posedge clk) begin ptp_ts_out_reg <= ptp_ts_out_next; start_packet_reg <= 2'b00; - error_bad_frame_reg <= error_bad_frame_next; - error_bad_fcs_reg <= error_bad_fcs_next; - rx_bad_block_reg <= 1'b0; - rx_sequence_error_reg <= 1'b0; + + stat_rx_byte_reg <= stat_rx_byte_next; + stat_rx_pkt_len_reg <= stat_rx_pkt_len_next; + stat_rx_pkt_fragment_reg <= stat_rx_pkt_fragment_next; + stat_rx_pkt_jabber_reg <= stat_rx_pkt_jabber_next; + stat_rx_pkt_ucast_reg <= stat_rx_pkt_ucast_next; + stat_rx_pkt_mcast_reg <= stat_rx_pkt_mcast_next; + stat_rx_pkt_bcast_reg <= stat_rx_pkt_bcast_next; + stat_rx_pkt_vlan_reg <= stat_rx_pkt_vlan_next; + stat_rx_pkt_good_reg <= stat_rx_pkt_good_next; + stat_rx_pkt_bad_reg <= stat_rx_pkt_bad_next; + stat_rx_err_oversize_reg <= stat_rx_err_oversize_next; + stat_rx_err_bad_fcs_reg <= stat_rx_err_bad_fcs_next; + stat_rx_err_bad_block_reg <= 1'b0; + stat_rx_err_framing_reg <= 1'b0; + stat_rx_err_preamble_reg <= stat_rx_err_preamble_next; delay_type_valid <= 1'b0; @@ -416,15 +602,6 @@ always_ff @(posedge clk) begin ptp_ts_adj_reg[95:48] <= ptp_ts_reg[95:48] + 1; end - // start control character detection - if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_0) begin - lanes_swapped <= 1'b0; - input_start_d0 <= 1'b1; - end else if (encoded_rx_hdr == SYNC_CTRL && (encoded_rx_data[7:0] == BLOCK_TYPE_START_4 || encoded_rx_data[7:0] == BLOCK_TYPE_OS_START)) begin - lanes_swapped <= 1'b1; - input_start_swap <= 1'b1; - end - // lane swapping and termination character detection if (lanes_swapped) begin if (delay_type_valid) begin @@ -493,6 +670,16 @@ always_ff @(posedge clk) begin input_data_d0 <= encoded_rx_data_masked; end + // start control character detection + if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_0) begin + lanes_swapped <= 1'b0; + input_start_d0 <= 1'b1; + input_data_d0 <= encoded_rx_data_masked; + end else if (encoded_rx_hdr == SYNC_CTRL && (encoded_rx_data[7:0] == BLOCK_TYPE_START_4 || encoded_rx_data[7:0] == BLOCK_TYPE_OS_START)) begin + lanes_swapped <= 1'b1; + input_start_swap <= 1'b1; + end + if (encoded_rx_hdr == SYNC_DATA) begin delay_type <= INPUT_TYPE_DATA; end else if (encoded_rx_hdr == SYNC_CTRL) begin @@ -514,61 +701,61 @@ always_ff @(posedge clk) begin end // check for framing errors - rx_sequence_error_reg <= 1'b0; + stat_rx_err_framing_reg <= 1'b0; if (encoded_rx_hdr == SYNC_DATA) begin // data - must be in a frame - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end else if (encoded_rx_hdr == SYNC_CTRL) begin // control - control only allowed between frames frame_reg <= 1'b0; case (encoded_rx_data[7:4]) BLOCK_TYPE_CTRL[7:4]: begin - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_OS_4[7:4]: begin - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_START_4[7:4]: begin frame_reg <= 1'b1; - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_OS_START[7:4]: begin frame_reg <= 1'b1; - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_OS_04[7:4]: begin - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_START_0[7:4]: begin frame_reg <= 1'b1; - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_OS_0[7:4]: begin - rx_sequence_error_reg <= frame_reg; + stat_rx_err_framing_reg <= frame_reg; end BLOCK_TYPE_TERM_0[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_1[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_2[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_3[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_4[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_5[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_6[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end BLOCK_TYPE_TERM_7[7:4]: begin - rx_sequence_error_reg <= !frame_reg; + stat_rx_err_framing_reg <= !frame_reg; end default: begin // invalid block type @@ -603,12 +790,12 @@ always_ff @(posedge clk) begin BLOCK_TYPE_TERM_7: begin end default: begin // invalid block type - rx_bad_block_reg <= 1'b1; + stat_rx_err_bad_block_reg <= 1'b1; end endcase end else begin // invalid header - rx_bad_block_reg <= 1'b1; + stat_rx_err_bad_block_reg <= 1'b1; end // capture timestamps @@ -648,12 +835,24 @@ always_ff @(posedge clk) begin m_axis_rx_tvalid_reg <= 1'b0; start_packet_reg <= 2'b00; - error_bad_frame_reg <= 1'b0; - error_bad_fcs_reg <= 1'b0; - rx_bad_block_reg <= 1'b0; - rx_sequence_error_reg <= 1'b0; frame_reg <= 1'b0; + stat_rx_byte_reg <= '0; + stat_rx_pkt_len_reg <= '0; + stat_rx_pkt_fragment_reg <= 1'b0; + stat_rx_pkt_jabber_reg <= 1'b0; + stat_rx_pkt_ucast_reg <= 1'b0; + stat_rx_pkt_mcast_reg <= 1'b0; + stat_rx_pkt_bcast_reg <= 1'b0; + stat_rx_pkt_vlan_reg <= 1'b0; + stat_rx_pkt_good_reg <= 1'b0; + stat_rx_pkt_bad_reg <= 1'b0; + stat_rx_err_oversize_reg <= 1'b0; + stat_rx_err_bad_fcs_reg <= 1'b0; + stat_rx_err_bad_block_reg <= 1'b0; + stat_rx_err_framing_reg <= 1'b0; + stat_rx_err_preamble_reg <= 1'b0; + input_type_d0 <= INPUT_TYPE_IDLE; input_type_d1 <= INPUT_TYPE_IDLE; diff --git a/rtl/eth/taxi_eth_mac_phy_10g.sv b/rtl/eth/taxi_eth_mac_phy_10g.sv index 55d2b2f..2f32239 100644 --- a/rtl/eth/taxi_eth_mac_phy_10g.sv +++ b/rtl/eth/taxi_eth_mac_phy_10g.sv @@ -220,17 +220,29 @@ eth_mac_phy_10g_rx_inst ( */ .rx_start_packet(rx_start_packet), .rx_error_count(rx_error_count), - .rx_error_bad_frame(rx_error_bad_frame), - .rx_error_bad_fcs(rx_error_bad_fcs), - .rx_bad_block(rx_bad_block), - .rx_sequence_error(rx_sequence_error), .rx_block_lock(rx_block_lock), .rx_high_ber(rx_high_ber), .rx_status(rx_status), + .stat_rx_byte(), + .stat_rx_pkt_len(), + .stat_rx_pkt_fragment(), + .stat_rx_pkt_jabber(), + .stat_rx_pkt_ucast(), + .stat_rx_pkt_mcast(), + .stat_rx_pkt_bcast(), + .stat_rx_pkt_vlan(), + .stat_rx_pkt_good(), + .stat_rx_pkt_bad(rx_error_bad_frame), + .stat_rx_err_oversize(), + .stat_rx_err_bad_fcs(rx_error_bad_fcs), + .stat_rx_err_bad_block(rx_bad_block), + .stat_rx_err_framing(rx_sequence_error), + .stat_rx_err_preamble(), /* * Configuration */ + .cfg_rx_max_pkt_len(16'd9218), .cfg_rx_enable(cfg_rx_enable), .cfg_rx_prbs31_enable(cfg_rx_prbs31_enable) ); diff --git a/rtl/eth/taxi_eth_mac_phy_10g_rx.sv b/rtl/eth/taxi_eth_mac_phy_10g_rx.sv index 2b117bc..7d96e2d 100644 --- a/rtl/eth/taxi_eth_mac_phy_10g_rx.sv +++ b/rtl/eth/taxi_eth_mac_phy_10g_rx.sv @@ -57,17 +57,29 @@ module taxi_eth_mac_phy_10g_rx # */ output wire logic [1:0] rx_start_packet, output wire logic [6:0] rx_error_count, - output wire logic rx_error_bad_frame, - output wire logic rx_error_bad_fcs, - output wire logic rx_bad_block, - output wire logic rx_sequence_error, output wire logic rx_block_lock, output wire logic rx_high_ber, output wire logic rx_status, + output wire logic [3:0] stat_rx_byte, + output wire logic [15:0] stat_rx_pkt_len, + output wire logic stat_rx_pkt_fragment, + output wire logic stat_rx_pkt_jabber, + output wire logic stat_rx_pkt_ucast, + output wire logic stat_rx_pkt_mcast, + output wire logic stat_rx_pkt_bcast, + output wire logic stat_rx_pkt_vlan, + output wire logic stat_rx_pkt_good, + output wire logic stat_rx_pkt_bad, + output wire logic stat_rx_err_oversize, + output wire logic stat_rx_err_bad_fcs, + output wire logic stat_rx_err_bad_block, + output wire logic stat_rx_err_framing, + output wire logic stat_rx_err_preamble, /* * Configuration */ + input wire logic [15:0] cfg_rx_max_pkt_len = 16'd1518, input wire logic cfg_rx_enable, input wire logic cfg_rx_prbs31_enable ); @@ -107,8 +119,8 @@ eth_phy_10g_rx_if_inst ( /* * Status */ - .rx_bad_block(rx_bad_block), - .rx_sequence_error(rx_sequence_error), + .rx_bad_block(stat_rx_err_bad_block), + .rx_sequence_error(stat_rx_err_framing), .rx_error_count(rx_error_count), .rx_block_lock(rx_block_lock), .rx_high_ber(rx_high_ber), @@ -150,16 +162,28 @@ axis_baser_rx_inst ( /* * Configuration */ + .cfg_rx_max_pkt_len(cfg_rx_max_pkt_len), .cfg_rx_enable(cfg_rx_enable), /* * Status */ - .start_packet(rx_start_packet), - .error_bad_frame(rx_error_bad_frame), - .error_bad_fcs(rx_error_bad_fcs), - .rx_bad_block(rx_bad_block), - .rx_sequence_error(rx_sequence_error) + .rx_start_packet(rx_start_packet), + .stat_rx_byte(stat_rx_byte), + .stat_rx_pkt_len(stat_rx_pkt_len), + .stat_rx_pkt_fragment(stat_rx_pkt_fragment), + .stat_rx_pkt_jabber(stat_rx_pkt_jabber), + .stat_rx_pkt_ucast(stat_rx_pkt_ucast), + .stat_rx_pkt_mcast(stat_rx_pkt_mcast), + .stat_rx_pkt_bcast(stat_rx_pkt_bcast), + .stat_rx_pkt_vlan(stat_rx_pkt_vlan), + .stat_rx_pkt_good(stat_rx_pkt_good), + .stat_rx_pkt_bad(stat_rx_pkt_bad), + .stat_rx_err_oversize(stat_rx_err_oversize), + .stat_rx_err_bad_fcs(stat_rx_err_bad_fcs), + .stat_rx_err_bad_block(stat_rx_err_bad_block), + .stat_rx_err_framing(stat_rx_err_framing), + .stat_rx_err_preamble(stat_rx_err_preamble) ); endmodule diff --git a/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py b/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py index 4bfa214..700495d 100644 --- a/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py +++ b/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.py @@ -50,8 +50,28 @@ class TB: self.ptp_clock = PtpClockSimTime(ts_tod=dut.ptp_ts, clock=dut.clk) + dut.cfg_rx_max_pkt_len.setimmediatevalue(0) dut.cfg_rx_enable.setimmediatevalue(0) + self.stats = {} + self.stats["stat_rx_byte"] = 0 + self.stats["stat_rx_pkt_len"] = 0 + self.stats["stat_rx_pkt_fragment"] = 0 + self.stats["stat_rx_pkt_jabber"] = 0 + self.stats["stat_rx_pkt_ucast"] = 0 + self.stats["stat_rx_pkt_mcast"] = 0 + self.stats["stat_rx_pkt_bcast"] = 0 + self.stats["stat_rx_pkt_vlan"] = 0 + self.stats["stat_rx_pkt_good"] = 0 + self.stats["stat_rx_pkt_bad"] = 0 + self.stats["stat_rx_err_oversize"] = 0 + self.stats["stat_rx_err_bad_fcs"] = 0 + self.stats["stat_rx_err_bad_block"] = 0 + self.stats["stat_rx_err_framing"] = 0 + self.stats["stat_rx_err_preamble"] = 0 + + cocotb.start_soon(self._run_stats_counters()) + async def reset(self): self.dut.rst.setimmediatevalue(0) await RisingEdge(self.dut.clk) @@ -63,12 +83,25 @@ class TB: await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) + self.stats_reset() + + def stats_reset(self): + for stat in self.stats: + self.stats[stat] = 0 + + async def _run_stats_counters(self): + while True: + await RisingEdge(self.dut.clk) + for stat in self.stats: + self.stats[stat] += int(getattr(self.dut, stat).value) + async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): tb = TB(dut) tb.source.ifg = ifg + tb.dut.cfg_rx_max_pkt_len.value = 9218 tb.dut.cfg_rx_enable.value = 1 await tb.reset() @@ -76,9 +109,14 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): test_frames = [payload_data(x) for x in payload_lengths()] tx_frames = [] + total_bytes = 0 + total_pkts = 0 + for test_data in test_frames: test_frame = XgmiiFrame.from_payload(test_data, tx_complete=tx_frames.append) await tb.source.send(test_frame) + total_bytes += max(len(test_data), 60)+4 + total_pkts += 1 for test_data in test_frames: rx_frame = await tb.sink.recv() @@ -104,6 +142,114 @@ async def run_test(dut, payload_lengths=None, payload_data=None, ifg=12): assert tb.sink.empty() + for stat, val in tb.stats.items(): + tb.log.info("%s: %d", stat, val) + + assert tb.stats["stat_rx_byte"] == total_bytes + assert tb.stats["stat_rx_pkt_len"] == total_bytes + assert tb.stats["stat_rx_pkt_fragment"] == 0 + assert tb.stats["stat_rx_pkt_jabber"] == 0 + assert tb.stats["stat_rx_pkt_ucast"] == total_pkts + assert tb.stats["stat_rx_pkt_mcast"] == 0 + assert tb.stats["stat_rx_pkt_bcast"] == 0 + assert tb.stats["stat_rx_pkt_vlan"] == 0 + assert tb.stats["stat_rx_pkt_good"] == total_pkts + assert tb.stats["stat_rx_pkt_bad"] == 0 + assert tb.stats["stat_rx_err_oversize"] == 0 + assert tb.stats["stat_rx_err_bad_fcs"] == 0 + assert tb.stats["stat_rx_err_bad_block"] == 0 + assert tb.stats["stat_rx_err_framing"] == 0 + assert tb.stats["stat_rx_err_preamble"] == 0 + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_test_oversize(dut, ifg=12): + + tb = TB(dut) + + tb.source.ifg = ifg + tb.dut.cfg_rx_max_pkt_len.value = 1518 + tb.dut.cfg_rx_enable.value = 1 + + await tb.reset() + + for max_len in range(128-4-8, 128-4+9): + + tb.stats_reset() + + total_bytes = 0 + total_pkts = 0 + good_bytes = 0 + oversz_pkts = 0 + oversz_bytes_in = 0 + oversz_bytes_out = 0 + + for test_pkt_len in range(max_len-8, max_len+9): + + tb.log.info("max len %d (without FCS), test len %d (without FCS)", max_len, test_pkt_len) + + tb.dut.cfg_rx_max_pkt_len.value = max_len+4 + + test_data_1 = bytes(x for x in range(60)) + test_data_2 = bytes(x for x in range(test_pkt_len)) + + for k in range(3): + if k == 1: + test_data = test_data_2 + else: + test_data = test_data_1 + test_frame = XgmiiFrame.from_payload(test_data) + await tb.source.send(test_frame) + total_bytes += max(len(test_data), 60)+4 + total_pkts += 1 + if len(test_data) > max_len: + oversz_pkts += 1 + oversz_bytes_in += len(test_data)+4 + oversz_bytes_out += max_len + else: + good_bytes += len(test_data)+4 + + for k in range(3): + rx_frame = await tb.sink.recv() + + if k == 1: + if test_pkt_len > max_len: + frame_error = rx_frame.tuser[-1] & 1 + assert frame_error + else: + frame_error = rx_frame.tuser & 1 + assert rx_frame.tdata == test_data_2 + assert frame_error == 0 + else: + frame_error = rx_frame.tuser & 1 + assert rx_frame.tdata == test_data_1 + assert frame_error == 0 + + assert tb.sink.empty() + + for stat, val in tb.stats.items(): + tb.log.info("%s: %d", stat, val) + + assert tb.stats["stat_rx_byte"] >= good_bytes+oversz_bytes_out + assert tb.stats["stat_rx_byte"] <= good_bytes+oversz_bytes_in + assert tb.stats["stat_rx_pkt_len"] >= good_bytes+oversz_bytes_out + assert tb.stats["stat_rx_pkt_len"] <= good_bytes+oversz_bytes_in + assert tb.stats["stat_rx_pkt_fragment"] == 0 + assert tb.stats["stat_rx_pkt_jabber"] == 0 + assert tb.stats["stat_rx_pkt_ucast"] == total_pkts + assert tb.stats["stat_rx_pkt_mcast"] == 0 + assert tb.stats["stat_rx_pkt_bcast"] == 0 + assert tb.stats["stat_rx_pkt_vlan"] == 0 + assert tb.stats["stat_rx_pkt_good"] == total_pkts-oversz_pkts + assert tb.stats["stat_rx_pkt_bad"] == oversz_pkts + assert tb.stats["stat_rx_err_oversize"] == oversz_pkts + assert tb.stats["stat_rx_err_bad_fcs"] == 0 + assert tb.stats["stat_rx_err_bad_block"] == 0 + assert tb.stats["stat_rx_err_framing"] == 0 + assert tb.stats["stat_rx_err_preamble"] == 0 + await RisingEdge(dut.clk) await RisingEdge(dut.clk) @@ -128,6 +274,10 @@ if cocotb.SIM_NAME: factory.add_option("ifg", list(range(0, 13))) factory.generate_tests() + factory = TestFactory(run_test_oversize) + factory.add_option("ifg", list(range(0, 13))) + factory.generate_tests() + # cocotb-test diff --git a/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv b/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv index da81ab4..9fed152 100644 --- a/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv +++ b/tb/eth/taxi_axis_baser_rx_64/test_taxi_axis_baser_rx_64.sv @@ -39,13 +39,25 @@ taxi_axis_if #(.DATA_W(DATA_W), .USER_EN(1), .USER_W(USER_W)) m_axis_rx(); logic [PTP_TS_W-1:0] ptp_ts; +logic [15:0] cfg_rx_max_pkt_len; logic cfg_rx_enable; -logic [1:0] start_packet; -logic error_bad_frame; -logic error_bad_fcs; -logic rx_bad_block; -logic rx_sequence_error; +logic [1:0] rx_start_packet; +logic [3:0] stat_rx_byte; +logic [15:0] stat_rx_pkt_len; +logic stat_rx_pkt_fragment; +logic stat_rx_pkt_jabber; +logic stat_rx_pkt_ucast; +logic stat_rx_pkt_mcast; +logic stat_rx_pkt_bcast; +logic stat_rx_pkt_vlan; +logic stat_rx_pkt_good; +logic stat_rx_pkt_bad; +logic stat_rx_err_oversize; +logic stat_rx_err_bad_fcs; +logic stat_rx_err_bad_block; +logic stat_rx_err_framing; +logic stat_rx_err_preamble; taxi_axis_baser_rx_64 #( .DATA_W(DATA_W), @@ -77,16 +89,28 @@ uut ( /* * Configuration */ + .cfg_rx_max_pkt_len(cfg_rx_max_pkt_len), .cfg_rx_enable(cfg_rx_enable), /* * Status */ - .start_packet(start_packet), - .error_bad_frame(error_bad_frame), - .error_bad_fcs(error_bad_fcs), - .rx_bad_block(rx_bad_block), - .rx_sequence_error(rx_sequence_error) + .rx_start_packet(rx_start_packet), + .stat_rx_byte(stat_rx_byte), + .stat_rx_pkt_len(stat_rx_pkt_len), + .stat_rx_pkt_fragment(stat_rx_pkt_fragment), + .stat_rx_pkt_jabber(stat_rx_pkt_jabber), + .stat_rx_pkt_ucast(stat_rx_pkt_ucast), + .stat_rx_pkt_mcast(stat_rx_pkt_mcast), + .stat_rx_pkt_bcast(stat_rx_pkt_bcast), + .stat_rx_pkt_vlan(stat_rx_pkt_vlan), + .stat_rx_pkt_good(stat_rx_pkt_good), + .stat_rx_pkt_bad(stat_rx_pkt_bad), + .stat_rx_err_oversize(stat_rx_err_oversize), + .stat_rx_err_bad_fcs(stat_rx_err_bad_fcs), + .stat_rx_err_bad_block(stat_rx_err_bad_block), + .stat_rx_err_framing(stat_rx_err_framing), + .stat_rx_err_preamble(stat_rx_err_preamble) ); endmodule