部分信号列表:
input [15:0] dest_port ; //目的端口
input [15:0] sour_port ; //源端口
input [31:0] dest_ip ; //目的IP地址
input [31:0] sour_ip ; //源IP地址
input [15:0] din ; //输入的数据
input din_vld ;
input din_sop ;
input din_eop ;
output reg [15:0] dout ;
output reg dout_vld ;
output reg dout_sop ;
output reg dout_eop ;
长度:UDP报文的整个大小,最小为8个字节(仅为首部)。
输入的包文如下:
数据0 数据1 数据2 … 数据n-2 数据n-1
输出的包文如下:
UDP首部 数据0 数据1 … 数据n-2 数据n-1
UDP首部包括源端口、目的端口、长度和检验和。
首部的源端口和目的端口由输入信号sour_port和dest_port给出:
首部的长度包括UDP首部和UDP数据的长度,单位为字节。UDP首部长度固定为8字节,UDP数据长度来自于对输入包文的统计。
首部的检验和计算的是UDP伪首部、UDP首部和UDP数据的校验和。其计算方式为:
把伪首部添加到UDP上:
把所有位划分为16位(2字节)的字:
把所有16位的字相加,如果遇到进位,则将高于16字节的进位部分的值加到最低位上,举例,16’hBB5E+16’hFCED=17’h1B84B,则将1放到最低位,得到结果是16‘hB84C
将所有字相加得到的结果应该为一个16位的数,将该数取反则可以得到检验和checksum.
注意:UDP伪首部只用于计算检验和,是不用输出去的。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
首先,需要使用计数器来区分包头和数据
//计数器计数写入的数据字节长度
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)begin
cnt0 <= 0;
end
else begin
cnt0 <= cnt0 + 1'b1;
end
end
end
assign add_cnt0 = din_vld;
assign end_cnt0 = add_cnt0 && cnt0 == din_eop;
//数据FIFO的写使能和写数据
assign wr_en = din_vld ;
assign wdata = {din_sop,din_eop,din};
//信息FIFO的写使能和写数据
assign msg_wr_en = end_cnt0;
assign msg_wdata = {cnt0 + 1,sum_tmp_b};
//数据的校验和计算
always @(*)begin
if(din_sop && din_vld)
sum_tmp_a = din;
else if(din_vld)
sum_tmp_a = sum + din;
else
sum_tmp_a = sum;
end
assign sum_tmp_b = sum_tmp_a[16] + sum_tmp_a[15:0];
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
sum <= 0;
end
else begin
sum <= sum_tmp_b;
end
end
//UDP头部拼接
assign data_head = {sour_port,dest_port,udp_len,udp_sum};
assign pre_head = {sour_ip,dest_ip,8'h0,8'hd17,udp_len,data_head};
assign udp_len = msg_q[31:16] + 8;
assign udp_sum = ~sum_3_0;
//计数器发UDP首部,一共8个字节
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)begin
cnt <= 0;
end
else begin
cnt <= cnt + 1'b1;
end
end
end
assign add_cnt = flag == 0 && msg_empty == 0;
assign end_cnt = add_cnt && cnt == 5 - 1;//因为计算校验和需要四个流水时钟,计算完后在第五个时钟被组装发送出去
assign dout_eop_tmp = rd_en && q[16];
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
flag <= 0;
end
else if(end_cnt)begin
flag <= 1;
end
else if(dout_eop_tmp)begin
flag <= 0;
end
end
//////////////////////////////////////////////////////////////////////////
// 通过流水线计算出校验和 //
// 注意要在4拍内计算出来 //
//////////////////////////////////////////////////////////////////////////
assign sum_0_0_tmp = pre_head[159 -:16] + pre_head[143 -:16];
assign sum_0_1_tmp = pre_head[127 -:16] + pre_head[111 -:16];
assign sum_0_2_tmp = pre_head[95 -:16] + pre_head[79 -:16];
assign sum_0_3_tmp = pre_head[63 -:16] + pre_head[47 -:16];
assign sum_0_4_tmp = pre_head[31 -:16] + pre_head[15 -:16];
assign sum_0_5_tmp = msg_q[15 :0];
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
sum_0_0 <= 0;
sum_0_1 <= 0;
sum_0_2 <= 0;
sum_0_3 <= 0;
sum_0_4 <= 0;
sum_0_5 <= 0;
end
else if(add_cnt && cnt == 1-1)begin
sum_0_0 <= sum_0_0_tmp[16] + sum_0_0_tmp[15:0];
sum_0_1 <= sum_0_1_tmp[16] + sum_0_1_tmp[15:0];
sum_0_2 <= sum_0_2_tmp[16] + sum_0_2_tmp[15:0];
sum_0_3 <= sum_0_3_tmp[16] + sum_0_3_tmp[15:0];
sum_0_4 <= sum_0_4_tmp[16] + sum_0_4_tmp[15:0];
sum_0_5 <= sum_0_5_tmp[16] + sum_0_5_tmp[15:0];
end
end
assign sum_1_0_tmp = sum_0_0 + sum_0_1;
assign sum_1_1_tmp = sum_0_2 + sum_0_3;
assign sum_1_2_tmp = sum_0_4 + sum_0_5;
always @(posedge clk or negedge rst_n)begin
if(rst_n)begin
sum_1_0 <= 0;
sum_1_1 <= 0;
sum_1_2 <= 0;
end
else if(add_cnt && cnt == 2-1)begin
sum_1_0 <= sum_1_0_tmp[16] + sum_1_0_tmp[15:0];
sum_1_1 <= sum_1_1_tmp[16] + sum_1_1_tmp[15:0];
sum_1_2 <= sum_1_2_tmp[16] + sum_1_2_tmp[15:0];
end
end
assign sum_2_0_tmp = sum_1_0 + sum_1_1;
assign sum_2_1_tmp = sum_1_2 ;
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
sum_2_0 <= 0;
sum_2_1 <= 0;
end
else if(add_cnt && cnt == 3-1)begin
sum_2_0 <= sum_2_0_tmp[16] + sum_2_0_tmp[15:0];
sum_2_1 <= sum_2_1_tmp[16] + sum_2_1_tmp[15:0];
end
end
assign sum_3_0_tmp = sum_2_0 + sum_2_1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
sum_3_0 <= 0;
end
else if(add_cnt && cnt == 4-1)begin
sum_3_0 <= sum_3_0_tmp[16] + sum_3_0_tmp[15:0];
end
end
//数据FIFO的读使能
assign rd_en = flag == 1 && msg_empty == 0; //输出数据flag==1
//信息FIFO的读使能
assign msg_rd_en = dout_eop_tmp;
assign dout_eop_tmp = rd_en && q[16];
//dout
always @(posedge clk or negedge rst_n)begin
if(rst_n==0)begin
dout <= 0;
end
else if(add_cnt && cnt != 1-1)begin
dout <= data_head[63 - 16*(cnt-1) -:16];
end
else
dout <= q[15:0];
end
//dout_sop
always @(posedge clk or negedge rst_n)begin
if(rst_n===0)begin
dout_sop <= 0;
end
else begin
dout_sop <= add_cnt && cnt == 1-1;
end
end
//dout_eop
always @(posedge clk or negedge rst_n)begin
if(rst_n===0)begin
dout_eop <= 0;
end
else begin
dout_eop <= dout_eop_tmp;;
end
end
//dout_vld
always @(posedge clk or negedge rst_n)begin
if(rst_n===0)begin
dout_vld <= 0;
end
else begin
dout_vld <= rd_en || add_cnt;
end
end