目录
一、UDP协议简单介绍
二、UDP功能实现
三、仿真
一、UDP协议简单介绍
UDP协议和TCP协议同位于传输层,介于网络层(IP)和应用层之间:UDP数据部分为应用层报文,而UDP报文在IP中承载。
UDP 报文格式相对于简单,如下图:
源端口:端口号0-65535,1-1024保留端口号,为标准的服务端口
目的端口:无须多解释
UDP长度:header+data 总长度
UDP校验和:伪头部,头部,data 三部分校验和。
数据:上层应用层的数据。
UDP校验和计算:UDP校验和计算-CSDN博客
二、UDP功能实现
UDP_RX模块功能:接收IP层传递过来的数据,判断数据中的目的端口号是否与本节点的源端口号相同,同时执行UDP校验和计算。(由于此时的校验是对整个UDP首部+UDP伪首部+UDP数据进行校验,所以可以参考IP校验的方式,将数据暂存在一个RAM中,根据校验和的正确性控制地址的分配)。
UDP_TX模块功能:将上层传递过来的数据封装上UDP头,并进行UDP校验和计算。(此时的校验和计算可以先将封装完毕的UDP帧存储在一个RAM中,并在一帧的结尾单独对UDP校验和所在的地址进行操作)。
UDP_TX模块:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/05/22 10:38:55
// Design Name:
// Module Name: UDP_TX
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module UDP_TX#(parameter P_SOURCE_PORT = 16'd8080 ,parameter P_TARGET_PORT = 16'd8080
)(input i_clk ,input i_rst ,input [15:0] i_set_source_port ,input i_set_source_valid ,input [15:0] i_set_target_port ,input i_set_target_valid ,input [63:0] s_axis_user_data ,input [31:0] s_axis_user_user ,//16'dByteLen,16'dBrustinput [7 :0] s_axis_user_keep ,input s_axis_user_last ,input s_axis_user_valid ,output s_axis_user_ready ,output [63:0] m_axis_ip_data ,output [70:0] m_axis_ip_user ,//16'dByteLen,1'bMF,16'dlen,1'bsplit,8'dtype,13'doffset,16'dIDoutput [7 :0] m_axis_ip_keep ,output m_axis_ip_last ,output m_axis_ip_valid ,input m_axis_ip_ready
);reg [15:0] ri_set_source_port ;
reg [15:0] ri_set_target_port ;
reg [63:0] rs_axis_user_data ;
reg [31:0] rs_axis_user_user ;
reg [7 :0] rs_axis_user_keep ;
reg rs_axis_user_last ;
reg rs_axis_user_valid ;
reg rs_axis_user_ready ;
reg [63:0] rm_axis_ip_data ;
reg [70:0] rm_axis_ip_user ;
reg [7 :0] rm_axis_ip_keep ;
reg rm_axis_ip_last ;
reg rm_axis_ip_valid ;
reg r_fifo_data_rden ;
reg [15:0] r_cnt ;
reg [7 :0] r_last_keep ;
reg r_fifo_data_empty ;
reg r_fifo_data_empty_1d ;wire [63:0] w_fifo_data_dout ;
wire w_fifo_data_full ;
wire w_fifo_data_empty ;assign s_axis_user_ready = rs_axis_user_ready ;
assign m_axis_ip_data = rm_axis_ip_data ;
assign m_axis_ip_user = rm_axis_ip_user ;
assign m_axis_ip_keep = rm_axis_ip_keep ;
assign m_axis_ip_last = rm_axis_ip_last ;
assign m_axis_ip_valid = rm_axis_ip_valid ;
//将用户传输的数据缓存
FIFO_DATA_64X256 FIFO_DATA_64X256_u0 (.clk (i_clk ), .srst (i_rst ),.din (rs_axis_user_data ), .wr_en (rs_axis_user_valid ),.rd_en (r_fifo_data_rden ),.dout (w_fifo_data_dout ),.full (w_fifo_data_full ),.empty (w_fifo_data_empty )
);always@(posedge i_clk,posedge i_rst)
beginif(i_rst) beginr_fifo_data_empty <= 'd0;r_fifo_data_empty_1d <= 'd0;end else beginr_fifo_data_empty <= w_fifo_data_empty;r_fifo_data_empty_1d <= r_fifo_data_empty;end
end
//动态配置源端口、目的端口
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)ri_set_source_port <= P_SOURCE_PORT;else if(i_set_source_valid)ri_set_source_port <= i_set_source_port;else ri_set_source_port <= ri_set_source_port;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst)ri_set_target_port <= P_TARGET_PORT;else if(i_set_target_valid)ri_set_target_port <= i_set_target_port;else ri_set_target_port <= ri_set_target_port;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst) beginrs_axis_user_data <= 'd0;rs_axis_user_keep <= 'd0;rs_axis_user_last <= 'd0;rs_axis_user_valid <= 'd0;end else beginrs_axis_user_data <= s_axis_user_data ;rs_axis_user_keep <= s_axis_user_keep ;rs_axis_user_last <= s_axis_user_last ;rs_axis_user_valid <= s_axis_user_valid;end
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst) rs_axis_user_user <= 'd0;else if(s_axis_user_valid)rs_axis_user_user <= s_axis_user_user ;else rs_axis_user_user <= rs_axis_user_user;
end
//控制ready信号,当一帧输入时将ready信号拉低
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rs_axis_user_ready <= 'd1;else if(s_axis_user_last)rs_axis_user_ready <= 'd0;else if(r_fifo_data_empty_1d)rs_axis_user_ready <= 'd1;else rs_axis_user_ready <= rs_axis_user_ready;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_last_keep <= 'd0;else if(s_axis_user_last)r_last_keep <= s_axis_user_keep;else r_last_keep <= r_last_keep;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_cnt <= 'd0;else if(r_cnt == rs_axis_user_user[15:0])r_cnt <= 'd0;else if(r_fifo_data_rden || r_cnt)r_cnt <= r_cnt + + 1;else r_cnt <= r_cnt;
end
//控制fifo读使能,当FIFO不为空的时候开始读
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_fifo_data_rden <= 'd0;else if(r_cnt == rs_axis_user_user[15:0] - 1)r_fifo_data_rden <= 'd0;else if(!w_fifo_data_empty)r_fifo_data_rden <= 'd1;else r_fifo_data_rden <= r_fifo_data_rden;
end
//组UDP帧
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_ip_data <= 'd0;else case(r_cnt)0 :rm_axis_ip_data <= {ri_set_source_port,ri_set_target_port,rs_axis_user_user[31:16] + 16'd8,16'd0};//源端口号、目的端口号、UDP长度、UDP校验和(暂时为0)default :rm_axis_ip_data <= w_fifo_data_dout;endcase
end
//控制Keep信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_ip_keep <= 'd0;else if(r_cnt && r_cnt == rs_axis_user_user[15:0] - 0)rm_axis_ip_keep <= r_last_keep;else rm_axis_ip_keep <= 8'b1111_1111;
end
//控制Last信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_ip_last <= 'd0;else if(r_cnt && r_cnt == rs_axis_user_user[15:0] - 0)rm_axis_ip_last <= 'd1;else rm_axis_ip_last <= 'd0;
end
//控制Valid信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_ip_valid <= 'd0;else if(rm_axis_ip_last)rm_axis_ip_valid <= 'd0;else if(r_fifo_data_rden)rm_axis_ip_valid <= 'd1;else rm_axis_ip_valid <= rm_axis_ip_valid;
end//16'dByteLen,1'bMF,16'dlen,1'bsplit,8'dtype,13'doffset,16'dID
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_ip_user <= 'd0;else rm_axis_ip_user <= {rs_axis_user_user[31:16] + 16'd8,1'b0,rs_axis_user_user[15:0] + 16'd1,1'b0,8'd17,13'd0,16'd0};
endendmodule
UDP_RX模块:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/05/22 10:38:55
// Design Name:
// Module Name: UDP_RX
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module UDP_RX#(parameter P_SOURCE_PORT = 16'd8080 ,parameter P_TARGET_PORT = 16'd8080
)(input i_clk ,input i_rst ,input [15:0] i_set_source_port ,input i_set_source_valid ,input [15:0] i_set_target_port ,input i_set_target_valid ,input [63:0] s_axis_ip_data ,input [54:0] s_axis_ip_user ,//1'bMF,16'dlen,1'bsplit,8'dtype,13'doffset,16'dIDinput [7 :0] s_axis_ip_keep ,input s_axis_ip_last ,input s_axis_ip_valid ,
//上层数据output [63:0] m_axis_user_data ,output [31:0] m_axis_user_user ,output [7 :0] m_axis_user_keep ,output m_axis_user_last ,output m_axis_user_valid
);reg [15:0] ri_set_source_port ;
reg [15:0] ri_set_target_port ;
reg [63:0] rs_axis_ip_data ;
reg [54:0] rs_axis_ip_user ;
reg [7 :0] rs_axis_ip_keep ;
reg rs_axis_ip_last ;
reg rs_axis_ip_valid ;
reg [63:0] rm_axis_user_data ;
reg [31:0] rm_axis_user_user ;
reg [7 :0] rm_axis_user_keep ;
reg rm_axis_user_last ;
reg rm_axis_user_valid ;
reg [15:0] r_cnt ;
reg [15:0] r_source_port ;
reg [15:0] r_target_port ;
reg [15:0] r_len ;
reg [7 :0] r_last_keep ;
reg r_udp_flag ;
reg r_port_check ;assign m_axis_user_data = rm_axis_user_data ;
assign m_axis_user_user = rm_axis_user_user ;
assign m_axis_user_keep = rm_axis_user_keep ;
assign m_axis_user_last = rm_axis_user_last ;
assign m_axis_user_valid = rm_axis_user_valid ;always@(posedge i_clk,posedge i_rst)
beginif(i_rst) beginrs_axis_ip_data <= 'd0;rs_axis_ip_user <= 'd0;rs_axis_ip_keep <= 'd0;rs_axis_ip_last <= 'd0;rs_axis_ip_valid <= 'd0;end else beginrs_axis_ip_data <= s_axis_ip_data ;rs_axis_ip_user <= s_axis_ip_user ;rs_axis_ip_keep <= s_axis_ip_keep ;rs_axis_ip_last <= s_axis_ip_last ;rs_axis_ip_valid <= s_axis_ip_valid;end
end
//动态配置端口号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)ri_set_source_port <= P_SOURCE_PORT;else if(i_set_source_valid)ri_set_source_port <= i_set_source_port;else ri_set_source_port <= ri_set_source_port;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst)ri_set_target_port <= 'd0;else if(i_set_target_valid)ri_set_target_port <= i_set_target_port;else ri_set_target_port <= ri_set_target_port;
end
//保存最后一次的Keep信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_last_keep <= 'd0;else if(s_axis_ip_last)r_last_keep <= s_axis_ip_keep;else r_last_keep <= 8'b1111_1111;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_cnt <= 'd0;else if(rs_axis_ip_valid)r_cnt <= r_cnt + 1;else r_cnt <= 'd0;
end
//获取IP层传递过来的数据的源端口号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_source_port <= 'd0;else if(rs_axis_ip_valid && r_cnt == 0)r_source_port <= rs_axis_ip_data[63:48];else r_source_port <= r_source_port;
end
//获取IP层传递过来的数据的目的端口号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_target_port <= 'd0;else if(rs_axis_ip_valid && r_cnt == 0)r_target_port <= rs_axis_ip_data[47:32];else r_target_port <= r_target_port;
end
//检测获取的源端口号是否等于本节点的目的端口号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_port_check <= 'd0;else if(r_cnt == 1 && r_target_port != ri_set_source_port) r_port_check <= 'd0;else if(r_cnt == 1 && r_target_port == ri_set_source_port)r_port_check <= 'd1;else r_port_check <= r_port_check;
end
//获取数据净荷的长度
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)r_len <= 'd0;else if(rs_axis_ip_valid && r_cnt == 0)r_len <= rs_axis_ip_data[31:16] - 16'd8;else r_len <= r_len;
endalways@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_user_data <= 'd0;elserm_axis_user_data <= rs_axis_ip_data;
end
//控制向上传递的USER信号,其中r_len代表字节长度,(r_len - 16'd1) >> 16'd3代表以8字节为单位的传输次数
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_user_user <= 'd0;else rm_axis_user_user <= {r_len,((r_len - 16'd1) >> 16'd3) + 16'd1};
end
//控制keep信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst)rm_axis_user_keep <= 'd0;else if(rs_axis_ip_last)rm_axis_user_keep <= r_last_keep;else rm_axis_user_keep <= 8'b1111_1111;
end
//控制Last信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst) rm_axis_user_last <= 'd0;else if(rs_axis_ip_last && rm_axis_user_valid)rm_axis_user_last <= 'd1;else rm_axis_user_last <= 'd0;
end
//控制Valid信号
always@(posedge i_clk,posedge i_rst)
beginif(i_rst) rm_axis_user_valid <= 'd0;else if(rm_axis_user_last)rm_axis_user_valid <= 'd0;else if(rs_axis_ip_valid && r_cnt == 1 && r_port_check && r_udp_flag)rm_axis_user_valid <= 'd1;else rm_axis_user_valid <= rm_axis_user_valid;
end
//检查本次从IP层获取的信号是否为UDP数据
always@(posedge i_clk,posedge i_rst)
beginif(i_rst) r_udp_flag <= 'd0;else if(s_axis_ip_valid && !rs_axis_ip_valid && s_axis_ip_user[36:29] != 17)r_udp_flag <= 'd0;else if(s_axis_ip_valid && !rs_axis_ip_valid && s_axis_ip_user[36:29] == 17)r_udp_flag <= 'd1;else r_udp_flag <= r_udp_flag;
endendmodule
三、仿真
UDP_TX模块:
UDP_RX模块: