一、模块功能
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)begin
if(i_rst)begin
rs_axis_out_data <= 'd0;
rs_axis_out_user <= 'd0;
rs_axis_out_keep <= 'd0;
rs_axis_out_last <= 'd0;
rs_axis_out_valid <= 'd0;
end
else begin
rs_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
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)begin
r_fifo_rden_ff1 <= 'd0;
r_fifo_rden_ff2 <= 'd0;
end
else begin
r_fifo_rden_ff1 <= r_fifo_rden;
r_fifo_rden_ff2 <= r_fifo_rden_ff1;
end
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_fifo_data_out <= 'd0;
else
r_fifo_data_out <= w_fifo_data_out;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_last_user <= 'd0;
else
if(s_axis_out_last)
r_last_user <= s_axis_out_user;
else
r_last_user <= r_last_user;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_last_keep <= 'd0;
else
if(s_axis_out_last)
r_last_keep <= s_axis_out_keep;
else
r_last_keep <= r_last_keep;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
ri_set_source_ip <= P_SOURCE_IP;
else
if(i_set_source_valid)
ri_set_source_ip <= i_set_source_ip;
else
ri_set_source_ip <= ri_set_source_ip;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
ri_set_target_ip <= P_TARGET_IP;
else
if(i_set_target_valid)
ri_set_target_ip <= i_set_target_ip;
else
ri_set_target_ip <= ri_set_target_ip;
end
//当FIFO有数据时就开始读FIFO
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_fifo_rden <= 'd0;
else
if(!w_fifo_empty && r_cnt == 0)
r_fifo_rden <= 1'b1;
else if(w_fifo_empty)
r_fifo_rden <= 1'b0;
else
r_fifo_rden <= r_fifo_rden;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_cnt <= 'd0;
else
if(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;
else
r_cnt <= r_cnt;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
rs_axis_out_ready <= 'd1;
else
if(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;
else
rs_axis_out_ready <= rs_axis_out_ready ;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
rm_axis_mac_data <= 'd0;
else
if(!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]};
else
rm_axis_mac_data <= {r_fifo_data_out[31:0],w_fifo_data_out[63:32]};
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_hd_check_cnt <= 'd0;
else
if(s_axis_out_valid)
r_hd_check_cnt <= r_hd_check_cnt + 1;
else
r_hd_check_cnt <= 'd0;
end
//做首部校验和
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
r_header_check <= 'd0;
else
if(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]; //加进位之后,可能还会产生进位,所以要再加一次
else
r_header_check <= r_header_check;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
rm_axis_mac_user <= 'd0;
else
rm_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)begin
if(i_rst)
rm_axis_mac_keep <= 'd0;
else
if(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;
endcase
else 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
else
rm_axis_mac_keep <= 8'b1111_1111;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
rm_axis_mac_last <= 'd0;
else
if(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;
else
rm_axis_mac_last <= 'd0;
end
always@(posedge i_clk,posedge i_rst)begin
if(i_rst)
rm_axis_mac_valid <= 'd0;
else
if(!w_fifo_empty && r_cnt == 0)
rm_axis_mac_valid <= 1'b1;
else if(rm_axis_mac_last)
rm_axis_mac_valid <= 'd0;
else
rm_axis_mac_valid <= rm_axis_mac_valid ;
end