Skip to content

[udp_checksum_gen_64]: header drop on header fifo overflow #83

Open
@hannodewind

Description

@hannodewind

The udp_checksum_gen_64 module drops a header when the header fifo becomes full.

This happens due to ready latency in the header_fifo_ready path back to s_udp_hdr_ready.

On the first clock cycle the state machine is in STATE_IDLE after STATE_FINISH_SUM_2, hdr_valid_reg will be 1 due to the registered header commit in STATE_FINISH_SUM_2. If this commit fills the fifo, the fifo will be full on the next clock cycle. However, header_fifo_ready and thus s_udp_hdr_ready_next is still 1 in this clock cycle, thus s_udp_hdr_ready will be 1 in the next clock cycle even though the fifo will be full. This causes the state machine to register a new header and progress from STATE_IDLE on the next clock cycle if s_udp_hdr_valid = '1'. When the state machine finishes, it writes a final hdr_valid_next even though the fifo is full, and the header is then essentially dropped.

image

Picked this up in system. Replicated this in test_udp_checksum_64.py by running the following test (currently commented out other tests...)
It sends a bunch of packets into the fifo with the sink paused to force a fifo overflow condition. Not the best test, but it illustrates the point.

        yield clk.posedge
        payload_len = 8
        print("test 4: header fifo overflow with back-to-back packets, length %d" % payload_len)
        current_test.next = 4

        test_frame1 = udp_ep.UDPFrame()
        test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
        test_frame1.eth_src_mac = 0x5A5152535455
        test_frame1.eth_type = 0x0800
        test_frame1.ip_version = 4
        test_frame1.ip_ihl = 5
        test_frame1.ip_length = None
        test_frame1.ip_identification = 0
        test_frame1.ip_flags = 2
        test_frame1.ip_fragment_offset = 0
        test_frame1.ip_ttl = 64
        test_frame1.ip_protocol = 0x11
        test_frame1.ip_header_checksum = None
        test_frame1.ip_source_ip = 0xc0a80164
        test_frame1.ip_dest_ip = 0xc0a80165
        test_frame1.udp_source_port = 1
        test_frame1.udp_dest_port = 2
        test_frame1.udp_length = None
        test_frame1.udp_checksum = None
        test_frame1.payload = bytearray(range(payload_len))
        test_frame1.build()

        cnt = 50
        sink_pause.next = True
        yield clk.posedge

        for i in range(cnt):
            source.send(test_frame1)

        i = 8*cnt
        while i > 0:
            i = max(0, i-1)
            yield clk.posedge

        sink_pause.next = False
        yield clk.posedge

        for i in range(cnt):
            yield sink.wait()
            rx_frame = sink.recv()
        
        yield delay(100)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions