一、模块功能
1、上层数据封装IP报文头部
2、计算首部校验和
二、首部校验和计算方法
在发送方,先把IP数据报首部划分为许多16位字的序列,并把检验和字段置零。用反码算术运算把所有16位字相加后,将得到的和的反码写入检验和字段。接收方收到数据报后,将首部的所有16位字再使用反码算术运算相加一次。将得到的和取反码,即得出接收方检验和的计算结果。若首部未发生任何变化,则此结果必为0,于是就保留这个数据报。否则即认为出差错。
原文链接:https://blog.csdn.net/weixin_44870077/article/details/118106364
例如一包数据的首部:64‘h4500001400012000、64’h8017d0b9c0a86464、64‘hc0a8646300000000
版本号到片偏移:64‘h4500001400012000
生存时间:8’h80
协议号:8‘h17
计算出来的首部校验和:16’hd0b9
源IP地址:c0a86464
目的IP地址:c0a86463
划分为长度为16bit的字段:4500 0014 0001 2000 8017 首部校验和初始计算值0000 c0a8 6464 c0a8 6463
相加:4500 + 0014 + 0001 + 2000 + 8017 + 0000 + c0a8 + 6464 + c0a8 + 6463 = 3 2F43
进位的高位再次加到低16位:2F43 + 0003 = 2F46
按位取法之后得到:d0b9
三、程序设计
参考:奇哥FPGA
//将数据缓存到FIFO
FIFO_UDP_DATA_64X16 u_FIFO_UDP_DATA_64X16 (.clk (i_clk ), .srst (i_rst ), .din (rs_axis_out_data ), .wr_en (rs_axis_out_valid ), .rd_en (r_fifo_rden ), .dout (w_fifo_data_out ), .full (), .empty (w_fifo_empty )
);always@(posedge i_clk,posedge i_rst)beginif(i_rst)beginrs_axis_out_data <= 'd0; rs_axis_out_user <= 'd0;rs_axis_out_keep <= 'd0;rs_axis_out_last <= 'd0;rs_axis_out_valid <= 'd0;endelse beginrs_axis_out_data <= s_axis_out_data ;rs_axis_out_user <= s_axis_out_user ;rs_axis_out_keep <= s_axis_out_keep ;rs_axis_out_last <= s_axis_out_last ;rs_axis_out_valid <= s_axis_out_valid ;end
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)beginr_fifo_rden_ff1 <= 'd0;r_fifo_rden_ff2 <= 'd0;endelse beginr_fifo_rden_ff1 <= r_fifo_rden;r_fifo_rden_ff2 <= r_fifo_rden_ff1;end
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)r_fifo_data_out <= 'd0;elser_fifo_data_out <= w_fifo_data_out;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)r_last_user <= 'd0;elseif(s_axis_out_last)r_last_user <= s_axis_out_user;elser_last_user <= r_last_user;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)r_last_keep <= 'd0;elseif(s_axis_out_last)r_last_keep <= s_axis_out_keep;elser_last_keep <= r_last_keep;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)ri_set_source_ip <= P_SOURCE_IP;elseif(i_set_source_valid)ri_set_source_ip <= i_set_source_ip;elseri_set_source_ip <= ri_set_source_ip;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)ri_set_target_ip <= P_TARGET_IP;elseif(i_set_target_valid)ri_set_target_ip <= i_set_target_ip;elseri_set_target_ip <= ri_set_target_ip;
end
//当FIFO有数据时就开始读FIFO
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_fifo_rden <= 'd0;elseif(!w_fifo_empty && r_cnt == 0)r_fifo_rden <= 1'b1;else if(w_fifo_empty)r_fifo_rden <= 1'b0;elser_fifo_rden <= r_fifo_rden;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)r_cnt <= 'd0;elseif(rm_axis_mac_last)r_cnt <= 'd0;else if((!w_fifo_empty && r_cnt == 0 && m_axis_mac_ready)|| r_cnt)r_cnt <= r_cnt + 1;elser_cnt <= r_cnt;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)rs_axis_out_ready <= 'd1;elseif(s_axis_out_last || !m_axis_mac_ready)rs_axis_out_ready <= 'd0;else if(rm_axis_mac_last || (!rm_axis_mac_valid && !m_axis_mac_ready))rs_axis_out_ready <= 'd1;elsers_axis_out_ready <= rs_axis_out_ready ;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_mac_data <= 'd0;elseif(!w_fifo_empty && r_cnt == 0)rm_axis_mac_data <= {4'b0100,4'b0101,8'd0,(rs_axis_out_user[70:55] + 16'd20),rs_axis_out_user[15:0],{1'b0,rs_axis_out_user[54],~rs_axis_out_user[37]},rs_axis_out_user[28:16]};else if(r_cnt == 1)rm_axis_mac_data <= {8'd128,rs_axis_out_user[36:29],~r_header_check[15:0],ri_set_source_ip[31:0]};else if(r_cnt == 2)rm_axis_mac_data <= {ri_set_target_ip[31:0],w_fifo_data_out[63:32]};elserm_axis_mac_data <= {r_fifo_data_out[31:0],w_fifo_data_out[63:32]};
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)r_hd_check_cnt <= 'd0;elseif(s_axis_out_valid)r_hd_check_cnt <= r_hd_check_cnt + 1;elser_hd_check_cnt <= 'd0;
end//做首部校验和
always@(posedge i_clk,posedge i_rst)beginif(i_rst)r_header_check <= 'd0;elseif(r_hd_check_cnt == 1)r_header_check <= 16'h4500 + (rs_axis_out_user[70:55] + 16'd20) + rs_axis_out_user[15:0] + ({{1'b0,rs_axis_out_user[54],~rs_axis_out_user[37]},rs_axis_out_user[28:16]})+ {8'd128,rs_axis_out_user[36:29]} ++ ri_set_source_ip[31:16] + ri_set_source_ip[15:0] + ri_set_target_ip[31:16] + ri_set_target_ip[15:0];else if(r_hd_check_cnt == 1)r_header_check <= r_header_check[31:16] + r_header_check[15:0]; //可能会产生进位else if(r_hd_check_cnt == 2)r_header_check <= r_header_check[31:16] + r_header_check[15:0]; //加进位之后,可能还会产生进位,所以要再加一次elser_header_check <= r_header_check;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_mac_user <= 'd0;elserm_axis_mac_user <= {((rs_axis_out_user[70:55] + 16'd19) >> 3) + 1,48'hFFFFFFFF_FFFF,16'h0800};
end
//字节对齐
always@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_mac_keep <= 'd0;elseif(w_fifo_rden_neg && r_last_keep <= 8'b1111_0000)case(r_last_keep)// 8'b1111_1111: rm_axis_mac_keep <= 8'b1111_1111// 8'b1111_1110: rm_axis_mac_keep <= // 8'b1111_1100: rm_axis_mac_keep <=// 8'b1111_1000: rm_axis_mac_keep <=8'b1111_0000: rm_axis_mac_keep <= 8'b1111_1111;8'b1110_0000: rm_axis_mac_keep <= 8'b1111_1110;8'b1100_0000: rm_axis_mac_keep <= 8'b1111_1100;8'b1000_0000: rm_axis_mac_keep <= 8'b1111_1000;default : rm_axis_mac_keep <= 8'b1111_1111;endcaseelse if(w_fifo_rden_neg_ff1 && r_last_keep >= 8'b1111_1000)case(r_last_keep)8'b1111_1111: rm_axis_mac_keep <= 8'b1111_0000;8'b1111_1110: rm_axis_mac_keep <= 8'b1110_0000;8'b1111_1100: rm_axis_mac_keep <= 8'b1100_0000;8'b1111_1000: rm_axis_mac_keep <= 8'b1000_0000;// 8'b1111_0000: rm_axis_mac_keep <= 8'b1111_1111;// 8'b1110_0000: rm_axis_mac_keep <= 8'b1111_1110;// 8'b1100_0000: rm_axis_mac_keep <= 8'b1111_1100;// 8'b1000_0000: rm_axis_mac_keep <= 8'b1111_1000;default : rm_axis_mac_keep <= 8'b0000_0000;endcase elserm_axis_mac_keep <= 8'b1111_1111;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_mac_last <= 'd0;elseif(w_fifo_rden_neg && r_last_keep <= 8'b1111_0000)rm_axis_mac_last <= 1'b1;else if(w_fifo_rden_neg_ff1 && r_last_keep >= 8'b1111_1000)rm_axis_mac_last <= 1'b1;elserm_axis_mac_last <= 'd0;
endalways@(posedge i_clk,posedge i_rst)beginif(i_rst)rm_axis_mac_valid <= 'd0;elseif(!w_fifo_empty && r_cnt == 0)rm_axis_mac_valid <= 1'b1;else if(rm_axis_mac_last)rm_axis_mac_valid <= 'd0;elserm_axis_mac_valid <= rm_axis_mac_valid ;end