Electronic – Ethernet packet dump in FPGA memory getting corrupted

ethernetverilog

I am a beginner at Verilog and FPGA programming. My background is C/C++ software development.
I am developing a FPGA module which would basically read Ethernet network packets and then interact with a process running in software. As a start I wrote a packet snooper module, which would dump the next packet in its memory when a signal is enabled.

When I read the dumped packet using Avalon-MM interface with my module, the first 4 bytes seem to be corrupted. Further bytes are as expected.

In my test case, the first 4 bytes of dumped memory are always 0x76696365
I then modified my code to copy the first 4 bytes of the packet to a separate register. When I queried this register, I get the expected value, which is equal to 0xf531a in my test. But still, offset 0 of the packet dump memory is 0x76696365.

I am pasting the verilog code for your reference. Any suggestions on how to debug this issue?

module packet_snooper #(
  parameter MAC_ERROR_WIDTH = 6,
  parameter MAC_DATA_WIDTH  = 32,  // 32 or 64
  parameter CSR_ADDRESS_BITS = 12,
  parameter CSR_DATABUS_WIDTH = 32
) (
    input mac_clk,
    input app_clk,
    input reset_n_mac,
    input reset_n_app,

    // Avalon-ST interface from the MAC (can be 32-bits at 312.5MHz or 64-bits at 156.25Mhz)
    input                                stream_in_startofpacket,
    input                                stream_in_endofpacket,
    input                                stream_in_valid,
    output                               stream_in_ready,
    input [MAC_DATA_WIDTH-1:0]           stream_in_data,
    input [2-1:0] stream_in_empty,
    input [MAC_ERROR_WIDTH-1:0]          stream_in_error,

    // out
    output                                stream_out_startofpacket,
    output                                stream_out_endofpacket,
    output                                stream_out_valid,
    input                                 stream_out_ready,
    output [MAC_DATA_WIDTH-1:0]           stream_out_data,
    output [2-1:0] stream_out_empty,
    output [MAC_ERROR_WIDTH-1:0]          stream_out_error,

    // Avalon-MM bus
    input  [CSR_ADDRESS_BITS-1:0]       avs_csr_address,
    input                               avs_csr_read,
    input                               avs_csr_write,
    input  [CSR_DATABUS_WIDTH-1:0]      avs_csr_writedata,
    output reg [CSR_DATABUS_WIDTH-1:0]  avs_csr_readdata,
    output                              avs_csr_waitrequest
  );

parameter CSR_MODULE_ID = 32'h20001001;
parameter CSR_REG_LOAD_PACKET = 10'd1;
parameter CSR_REG_PACKET_LEN  = 10'd2;
parameter CSR_REG_DEBUG  = 10'd3;
parameter CSR_REG_DEBUG_NUM_SOP  = 10'd4;
parameter CSR_REG_PKT_BUF_BASE = 10'd5;

parameter PKT_BUFFER_BYTES = 2048;

reg dump_next_packet;
reg [2:0] resync_dnp;
reg resync_dnp_rising_edge;
reg resync_dnp_rising_edge_hold;
reg dump_pkt;
wire valid_dump;
reg [3:0] debug_sop;
reg [3:0] debug_eop;
reg [3:0] debug_ready;
reg [3:0] debug_valid;
reg [3:0] debug_ready_valid;
wire [31:0] debug_register;
reg [31:0] sop;
reg [31:0] num_sop;

reg [MAC_DATA_WIDTH-1:0] pkt_buffer [9:0];                     //((PKT_BUFFER_BYTES<<3)/MAC_DATA_WIDTH):0
reg [31:0] pkt_len;

//passthrough data
assign stream_out_startofpacket = stream_in_startofpacket;
assign stream_out_endofpacket = stream_in_endofpacket;
assign stream_out_valid = stream_in_valid;
assign stream_in_ready = stream_out_ready;
assign stream_out_data = stream_in_data;
assign stream_out_empty = stream_in_empty;
assign stream_out_error = stream_in_error;

assign avs_csr_waitrequest = 0;

assign debug_register = {12'h0, debug_ready_valid, debug_valid, debug_ready, debug_sop, debug_eop};

always @ (posedge mac_clk) begin //{
  if(~reset_n_mac) begin
    debug_ready <= 0;
    debug_valid <= 0;
    debug_ready_valid <= 0;
    debug_sop <= 0;
    debug_eop <= 0;
  end
  else begin 
  if (stream_out_ready)
    debug_ready <= debug_ready + 1;

  if (stream_in_valid)
    debug_valid <= debug_valid + 1;

  if (stream_in_valid && stream_out_ready)
    debug_ready_valid <= debug_ready_valid + 1;

  if (stream_in_valid && stream_in_startofpacket)
    debug_sop <= debug_sop + 1;

  if (stream_in_valid && stream_in_endofpacket)
    debug_eop <= debug_eop + 1;
  end
end //}

always @ (posedge mac_clk) begin //{
  if(~reset_n_mac) begin
    pkt_len <= 0;
    num_sop <= 0;
  end 
  else if(stream_in_valid && stream_out_ready) begin //{
    if (valid_dump) begin //{
      if (stream_in_startofpacket) begin
        pkt_len <= 1;
        pkt_buffer[0] <= stream_in_data;
        sop <= stream_in_data;
        num_sop <= num_sop + 1;
      end
      else begin
        pkt_len <= pkt_len + 1;
        pkt_buffer[pkt_len] <= stream_in_data; /* TODO: Handle stream_in_empty */
      end
    end //}
  end //}
end //}

//read registers
always @ (posedge app_clk) begin //{
  if (avs_csr_read) begin //{
    case(avs_csr_address)
    9'h0             : avs_csr_readdata <= CSR_MODULE_ID;
    CSR_REG_LOAD_PACKET : avs_csr_readdata <= dump_next_packet;
    CSR_REG_PACKET_LEN  : avs_csr_readdata <= (pkt_len <<     $clog2(MAC_DATA_WIDTH/8));
    CSR_REG_DEBUG : avs_csr_readdata <= sop;
    CSR_REG_DEBUG_NUM_SOP: avs_csr_readdata <= num_sop;
    default           : //{
        avs_csr_readdata <= pkt_buffer[avs_csr_address[9:0] - CSR_REG_PKT_BUF_BASE];  //TODO: handle 64-bit width
    //}
    endcase
  end //}
end //}

// write reg
always @ (posedge app_clk) begin //{
  if(~reset_n_app) begin //{
    dump_next_packet <= 0;
  end //}
  else if(avs_csr_write) begin //{
    case(avs_csr_address) 
      CSR_REG_LOAD_PACKET : dump_next_packet <= avs_csr_writedata; 
    endcase
  end //}
end //}

/* Synchronize dump_next_packet with mac_clk */
always @(posedge mac_clk) begin //{
  resync_dnp <= {dump_next_packet, resync_dnp[2:1]};
  resync_dnp_rising_edge <= resync_dnp[1] & !resync_dnp[0];
end //}

/* Hold the edge till current packet dump is complete */
always @ (posedge mac_clk) begin //{
  if(~reset_n_mac) 
    resync_dnp_rising_edge_hold <= 0;
  else if(dump_pkt & stream_in_endofpacket & stream_in_valid)
    resync_dnp_rising_edge_hold <= 0;
  else if(resync_dnp_rising_edge)
    resync_dnp_rising_edge_hold <= 1;
end //}

always @ (posedge mac_clk) begin //{
  if(~reset_n_mac) 
    dump_pkt <= 0;
  else if(dump_pkt & stream_in_endofpacket & stream_in_valid)
    dump_pkt <= 0;
  else if(resync_dnp_rising_edge_hold & stream_in_startofpacket & stream_in_valid)
    dump_pkt <= 1;
end //}

assign valid_dump = stream_in_valid & (dump_pkt || (stream_in_startofpacket & resync_dnp_rising_edge_hold));

endmodule

Best Answer

multiple always blocks with different clocks creates problem sometimes, so avoid using multiple clocking signals in the same module and make separate module for different clocks as far as possible.hope your problem get solved..