软件版本:Anlogic -TD5.9.1-DR1_ES1.1
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板
板卡获取平台:https://milianke.tmall.com/
登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
目录
[3.5 UDP层](#3.5 UDP层)
[3.5.1 UDP接收模块](#3.5.1 UDP接收模块)
[3.5.2 UDP发送模块](#3.5.2 UDP发送模块)
3.5 UDP层
该层实现用户数据和UDP报文的互转,相比于其它层次的设计,该层的逻辑相对简单。
3.5.1 UDP接收模块
通过计数器将UDP报文头部信息拆解,提取出端口号和长度信息。通过提取的长度对有效数据进行计数,从而得到有效数据并发送给用户端。
cpp
always@(posedge I_R_udp_clk or posedge I_reset) begin
if(I_reset) begin
cnt <= 4'd0;
O_R_udp_valid <= 1'b0;
O_R_udp_data <= 8'd0;
O_R_udp_len <= 16'd0;
udp_src_port <= 16'd0;
udp_dest_port <= 16'd0;
udp_pkg_len <= 16'd0;
udp_data_cnt <= 16'd0;
end
else if(I_udp_ip_rvalid) begin
udp_data_cnt <= udp_data_cnt + 1'b1;
case(cnt)
0 :begin udp_src_port[15:8] <= I_udp_ip_rdata; cnt <= cnt + 1'b1;end //UDP接收源端口(远程主机端口)
1 :begin udp_src_port[7:0] <= I_udp_ip_rdata; cnt <= cnt + 1'b1;end //UDP接收源端口(远程主机端口)
2 :begin udp_dest_port[15:8] <= I_udp_ip_rdata; cnt <= cnt + 1'b1;end //UDP接收目的端口(本地主机端口)
3 :begin udp_dest_port[7:0] <= I_udp_ip_rdata; cnt <= cnt + 1'b1;end //UDP接收目的端口(本地主机端口)
4 :begin udp_pkg_len[15:8] <= I_udp_ip_rdata; cnt <= cnt + 1'b1;end //UDP数据包长度
5 :begin udp_pkg_len[7:0] <= I_udp_ip_rdata; cnt <= cnt + 1'b1;end //UDP数据包长度
6 :begin cnt <= cnt + 1'b1;end //跳过检验和
7 :begin cnt <= cnt + 1'b1;end //跳过校验和
8 :begin
O_R_udp_valid <= 1'b1; //UDP接收数据有效
O_R_udp_data <= I_udp_ip_rdata;
O_R_udp_len <= udp_pkg_len - 16'd8;
cnt <= cnt + 1'b1;
end
9 :begin
if(udp_pkg_len < 16'd26) begin
if(udp_data_cnt == udp_pkg_len) begin
O_R_udp_valid <= 1'b0;
O_R_udp_data <= 8'd0;
cnt <= cnt + 1'b1;
end
else begin
O_R_udp_valid <= 1'b1;
O_R_udp_data <= I_udp_ip_rdata;
cnt <= cnt;
end
end
else begin
O_R_udp_valid <= 1'b1;
O_R_udp_data <= I_udp_ip_rdata;
cnt <= cnt;
end
end
10 :begin
O_R_udp_valid <= 1'b0;
O_R_udp_data <= 8'd0;
cnt <= cnt;
end
default: cnt <= 4'd0;
endcase
end
else if(!I_udp_ip_rvalid) begin
udp_pkg_len <= 16'd0;
udp_src_port <= 16'd0;
udp_dest_port <= 16'd0;
udp_data_cnt <= 16'd0;
O_R_udp_len <= 16'd0;
O_R_udp_data <= 8'd0;
O_R_udp_valid <= 1'b0;
cnt <= 4'd0;
end
end
3.5.2 UDP发送模块
状态机转换图如下:
IDLE:当用户端发送写请求,且uiip_tx模块不忙时,进入WAIT_ACK状态。
WAIT_ACK:等待uiip_tx模块将udp_ip_tbusy信号拉高,完成握手,进入SEND_UDP_HEADER状态,开始发送UDP报文头部。
SEND_UDP_HEADER:将8个字节的UDP报文头部添加在有效数据之前,头部数据发送完成后,进入SEND_UDP_PACKET状态。
SEND_UDP_PACKET:将经过shift_ram移位8位的数据拼接在包头之后,通过计数器判断发送数据的数量,待数据发送完成后,回到IDLE状态,等待下一次发送请求。
cpp
always@(posedge I_W_udp_clk or posedge I_reset) begin
if(I_reset) begin
cnt <= 4'd0;
O_udp_ip_tvalid <= 1'b0;
O_udp_ip_tdata <= 8'd0;
O_udp_ip_tpkg_len <= 16'd0;
trans_data_cnt <= 16'd0;
STATE <= IDLE;
end
else begin
case(STATE)
IDLE:begin
if(I_W_udp_req & (~I_udp_ip_tbusy)) //当有写UDP请求,并且ip_tx模块不忙(当I_udp_ip_tbusy=1代表正在ip层正在传输数据)
STATE <= WAIT_ACK; //进入WAIT_ACK
else
STATE <= IDLE;
end
WAIT_ACK:begin
if(I_udp_ip_tbusy) //如果ip_tx模块准备好,代表udp_layer可以发送数据
STATE <= SEND_UDP_HEADER;
else
STATE <= WAIT_ACK;
end
SEND_UDP_HEADER:begin
case(cnt)
0 :begin
if(I_W_udp_valid) begin
O_udp_ip_tvalid <= 1'b1; //udp包数据有效
O_udp_ip_tdata <= I_udp_local_port[15:8]; //UDP报文源端口
O_udp_ip_tpkg_len <= I_W_udp_len + 16'h0008; //UDP报文长度,其中8bytes为udp首部
cnt <= cnt + 1'b1;
end
else
cnt <= 0;
end
1 :begin
O_udp_ip_tdata <= I_udp_local_port[7:0]; //UDP报文源端口
cnt <= cnt + 1'b1;
end
2 :begin
O_udp_ip_tdata <= I_udp_dest_port[15:8]; //UDP报文目的端口
cnt <= cnt + 1'b1;
end
3 :begin
O_udp_ip_tdata <= I_udp_dest_port[7:0]; //UDP报文目的端口
cnt <= cnt + 1'b1;
end
4 :begin
O_udp_ip_tdata <= O_udp_ip_tpkg_len[15:8];//UDP报文长度
cnt <= cnt + 1'b1;
end
5 :begin
O_udp_ip_tdata <= O_udp_ip_tpkg_len[7:0]; //UDP报文长度
cnt <= cnt + 1'b1;
end
6 :begin
O_udp_ip_tdata <= CHECKSUM[7:0]; //校验和
cnt <= cnt + 1'b1;
end
7 :begin
O_udp_ip_tdata <= CHECKSUM [7:0]; //校验和
cnt <= 0;
STATE <= SEND_UDP_PACKET;
end
default: cnt <= 0;
endcase
end
SEND_UDP_PACKET:begin
if(trans_data_cnt != (O_udp_ip_tpkg_len - 16'd8)) begin
O_udp_ip_tvalid <= 1'b1;
O_udp_ip_tdata <= shift_data_out;
trans_data_cnt <= trans_data_cnt + 1'b1;
STATE <= SEND_UDP_PACKET;
end
else begin
trans_data_cnt <= 16'd0;
O_udp_ip_tdata <= 8'd0;
O_udp_ip_tvalid <= 1'b0;
O_udp_ip_tpkg_len <= 16'd0;
cnt <= 0;
STATE <= IDLE;
end
end
default: STATE <= IDLE;
endcase
end
end