alexforencich / verilog-ethernet

Verilog Ethernet components for FPGA implementation
MIT License
2.31k stars 706 forks source link

ip_64 flushes one payload transfer too many after ARP cache miss #155

Open paul-demo opened 1 year ago

paul-demo commented 1 year ago

I haven't simulated this; I have just been looking at your code to see if verilog-ethernet could be a compatible replacement for a similar, lesser version that I wrote and shipped in a previous project.

I was looking at what happens when there's an ARP cache miss when trying to send a Tx packet. In ip_64.v it looks like the top of tree implementation would drain one too many transfers from the payload stream, since drop_packet_reg would remain asserted into the first cycle where state becomes STATE_IDLE. This means that s_ip_payload_axis_tready would be asserted and consequently the s_ip_payload_axis stream could silently lose 8 bytes of data after every packet where a cache miss occurred if the upstream source of payload data is still asserting tvalid.

      STATE_WAIT_PACKET: begin
          drop_packet_next = drop_packet_reg;

          // wait for packet transfer to complete
          if (s_ip_payload_axis_tlast && s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
              state_next = STATE_IDLE;
          end else begin
              state_next = STATE_WAIT_PACKET;
          end
      end

I'll leave it to you to verify, but it seems like you need to conditionally set drop_packet_next as shown below, instead. I could be wrong though -- again, I haven't simulated this.

      STATE_WAIT_PACKET: begin
          // wait for packet transfer to complete
          if (s_ip_payload_axis_tlast && s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
              state_next = STATE_IDLE;
              drop_packet_next = 1'b0;
          end else begin
              state_next = STATE_WAIT_PACKET;
              drop_packet_next = drop_packet_reg;
          end
      end
paul-demo commented 1 year ago

In other words, I think you've assumed that the payload stream deasserts tvalid in the cycle after the tlast transfer, something which is not necessarily true. As far as I know from the AXI4-STREAM AMBA spec, you can have a transfer the cycle immediately following tlast.

An example would be an upstream FIFO that simply packs the tlast bit adjacent to tdata for each beat: if the FIFO was storing more than one packet, it would immediately assert tvalid in the cycle after tlast, and the first beat of the second packet would get lost due to this bug (again, not 100% sure since I have not simulated it).

alexforencich commented 1 year ago

Yep, I think you're right about that being a problem corner case. Looks like it probably affects both the 1G and the 10G modules.