diff --git a/rtl/eth/taxi_axis_xgmii_rx_32.sv b/rtl/eth/taxi_axis_xgmii_rx_32.sv index 1c18515..161247a 100644 --- a/rtl/eth/taxi_axis_xgmii_rx_32.sv +++ b/rtl/eth/taxi_axis_xgmii_rx_32.sv @@ -45,16 +45,31 @@ module taxi_axis_xgmii_rx_32 # /* * Configuration */ + input wire logic [15:0] cfg_rx_max_pkt_len = 16'd1518, input wire logic cfg_rx_enable, /* * Status */ - output wire logic start_packet, - output wire logic error_bad_frame, - output wire logic error_bad_fcs + output wire logic rx_start_packet, + output wire logic [2: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; @@ -106,6 +121,15 @@ logic xgmii_start_d0 = 1'b0; logic xgmii_start_d1 = 1'b0; logic xgmii_start_d2 = 1'b0; +logic frame_oversize_reg = 1'b0, frame_oversize_next; +logic pre_ok_reg = 1'b0, pre_ok_next; +logic [1: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; @@ -113,8 +137,22 @@ 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 start_packet_reg = 1'b0, start_packet_next; -logic error_bad_frame_reg = 1'b0, error_bad_frame_next; -logic error_bad_fcs_reg = 1'b0, error_bad_fcs_next; + +logic [2: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, stat_rx_err_bad_block_next; +logic stat_rx_err_framing_reg = 1'b0, stat_rx_err_framing_next; +logic stat_rx_err_preamble_reg = 1'b0, stat_rx_err_preamble_next; logic [PTP_TS_W-1:0] ptp_ts_out_reg = '0, ptp_ts_out_next; @@ -142,9 +180,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_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; wire last_cycle = state_reg == STATE_LAST; @@ -168,6 +220,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 = xgmii_rxd_d2; m_axis_rx_tkeep_next = {KEEP_W{1'b1}}; m_axis_rx_tvalid_next = 1'b0; @@ -177,27 +238,78 @@ always_comb begin ptp_ts_out_next = ptp_ts_out_reg; start_packet_next = 1'b0; - 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_bad_block_next = 1'b0; + stat_rx_err_framing_next = 1'b0; + stat_rx_err_preamble_next = 1'b0; + + // counter to measure frame length + if (&frame_len_reg[15:2] == 0) begin + if (term_present_reg) begin + frame_len_next = frame_len_reg + 16'(term_lane_reg); + end else begin + frame_len_next = frame_len_reg + 16'(CTRL_W); + end + end else begin + frame_len_next = '1; + end + + // counter for max frame length enforcement + if (frame_len_lim_reg[15:2] != 0) begin + frame_len_lim_next = frame_len_lim_reg - 16'(CTRL_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) + 2'd0: begin + is_mcast_next = xgmii_rxd_d2[0]; + is_bcast_next = &xgmii_rxd_d2; + end + 2'd1: is_bcast_next = is_bcast_reg && &xgmii_rxd_d2[15:0]; + 2'd3: is_8021q_next = {xgmii_rxd_d2[7:0], xgmii_rxd_d2[15:8]} == 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'(CTRL_W); + frame_len_lim_next = cfg_rx_max_pkt_len; + hdr_ptr_next = 0; + + pre_ok_next = xgmii_rxd_d2[31:8] == 24'h555555; + if (xgmii_start_d2 && cfg_rx_enable) begin // start condition if (framing_error_reg) begin // control or error characters in first data word - m_axis_rx_tdata_next = xgmii_rxd_d2; - m_axis_rx_tkeep_next = 4'h1; - m_axis_rx_tvalid_next = 1'b1; - m_axis_rx_tlast_next = 1'b1; - m_axis_rx_tuser_next = 1'b1; - error_bad_frame_next = 1'b1; + stat_rx_err_framing_next = 1'b1; state_next = STATE_IDLE; end else begin reset_crc = 1'b0; + stat_rx_byte_next = 3'(CTRL_W); state_next = STATE_PREAMBLE; end end else begin @@ -209,8 +321,21 @@ always_comb begin end STATE_PREAMBLE: begin // drop preamble - start_packet_next = 1'b1; - state_next = STATE_PAYLOAD; + + frame_len_lim_next = cfg_rx_max_pkt_len; + hdr_ptr_next = 0; + + pre_ok_next = pre_ok_reg && xgmii_rxd_d2 == 32'hD5555555; + + if (framing_error_reg) begin + // control or error characters in packet + stat_rx_err_framing_next = 1'b1; + state_next = STATE_IDLE; + end else begin + start_packet_next = 1'b1; + stat_rx_byte_next = 3'(CTRL_W); + state_next = STATE_PAYLOAD; + end end STATE_PAYLOAD: begin // read payload @@ -220,11 +345,29 @@ always_comb begin m_axis_rx_tlast_next = 1'b0; m_axis_rx_tuser_next = 1'b0; + if (term_present_reg) begin + stat_rx_byte_next = 3'(term_lane_reg); + frame_oversize_next = frame_len_lim_reg < 16'(4+4+term_lane_reg); + end else begin + stat_rx_byte_next = 3'(CTRL_W); + frame_oversize_next = frame_len_lim_reg < 4+4; + end + if (framing_error_reg) 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_framing_next = 1'b1; + 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 else if (term_present_reg) begin @@ -235,11 +378,29 @@ always_comb begin m_axis_rx_tlast_next = 1'b1; if (term_lane_reg == 0 && crc_valid_save[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 @@ -263,12 +424,31 @@ always_comb begin (term_lane_d0_reg == 2 && crc_valid_save[1]) || (term_lane_d0_reg == 3 && crc_valid_save[2])) 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 @@ -281,6 +461,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; @@ -290,8 +479,22 @@ always_ff @(posedge clk) begin ptp_ts_out_reg <= ptp_ts_out_next; start_packet_reg <= start_packet_next; - error_bad_frame_reg <= error_bad_frame_next; - error_bad_fcs_reg <= error_bad_fcs_next; + + 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 <= stat_rx_err_bad_block_next; + stat_rx_err_framing_reg <= stat_rx_err_framing_next; + stat_rx_err_preamble_reg <= stat_rx_err_preamble_next; term_lane_reg <= 0; term_present_reg <= 1'b0; @@ -332,8 +535,22 @@ always_ff @(posedge clk) begin m_axis_rx_tvalid_reg <= 1'b0; start_packet_reg <= 1'b0; - error_bad_frame_reg <= 1'b0; - error_bad_fcs_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; xgmii_rxc_d0 <= '0; diff --git a/rtl/eth/taxi_eth_mac_10g.sv b/rtl/eth/taxi_eth_mac_10g.sv index dfa2674..50169dc 100644 --- a/rtl/eth/taxi_eth_mac_10g.sv +++ b/rtl/eth/taxi_eth_mac_10g.sv @@ -297,14 +297,28 @@ end else if (DATA_W == 32) begin /* * Configuration */ + .cfg_rx_max_pkt_len(16'd9218), .cfg_rx_enable(cfg_rx_enable), /* * Status */ - .start_packet(rx_start_packet[0]), - .error_bad_frame(rx_error_bad_frame), - .error_bad_fcs(rx_error_bad_fcs) + .rx_start_packet(rx_start_packet[0]), + .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(), + .stat_rx_err_framing(), + .stat_rx_err_preamble() ); assign rx_start_packet[1] = 1'b0; diff --git a/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.py b/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.py index fb7f5f6..e2e5112 100644 --- a/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.py +++ b/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.py @@ -39,8 +39,29 @@ 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["rx_start_packet"] = 0 + 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) @@ -52,12 +73,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() @@ -65,9 +99,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() @@ -89,6 +128,116 @@ 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["rx_start_packet"] == total_pkts + 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["rx_start_packet"] == total_pkts + 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) @@ -113,6 +262,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_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.sv b/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.sv index 0f33baf..c58b0f5 100644 --- a/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.sv +++ b/tb/eth/taxi_axis_xgmii_rx_32/test_taxi_axis_xgmii_rx_32.sv @@ -38,11 +38,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 start_packet; -logic error_bad_frame; -logic error_bad_fcs; +logic rx_start_packet; +logic [2: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_xgmii_rx_32 #( .DATA_W(DATA_W), @@ -73,14 +87,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_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