软件版本: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层
该层实现用户数据和UDP报文的互转,相比于其它层次的设计,该层的逻辑相对简单。
3.5.1 UDP接收模块
通过计数器将UDP报文头部信息拆解,提取出端口号和长度信息。通过提取的长度对有效数据进行计数,从而得到有效数据并发送给用户端。
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状态,等待下一次发送请求。
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 |