赞
踩
前文链接:FPGA - 以太网UDP通信(一)
在以上文章中介绍了以太网简介,以太网UDP通信硬件结构,以及PHY芯片RGMII接口-GMII接口转换逻辑,以及数据链路层(MAC层)接受发送逻辑,IP层接受发送逻辑。接下来介绍UDP层接收发送逻辑。
在之前文章中已经介绍了UDP通信结构框图,如下:
UDP(User Datagram Protocol),用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。
UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但是正因为UDP协议的控制选项较少,在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如DNS、TFTP、SNMP等。 UDP在IP报文中的位置如下图所示:
UDP首部有8个字节,由4个字段构成,每个字段都是两个字节。
------------------------------------------------------------UDP首部---------------------------------------------------------
源端口 : 源端口号,需要对方回信时选用,不需要时全部置0。
目的端口 :目的端口号,在终点交付报文的时候需要用到。
长度 :UDP的数据报的长度(包括首部和数据)其最小值为8字节(只有首部),最大值为65535字节。
校验和 :检测UDP数据报在传输中是否有错,有错则丢弃。
该字段是可选的,当源主机不想计算校验和,则直接令该字段全为0。
---------------------------------------------------------------------------------------------------------------------------------
UDP层的接受和发送逻辑和mac层以及IP层的接受发送逻辑类似,和之前一样只需要在udp_receive中要完成数据解包校验,在udp_send中要完成数据组包,就完成了整个udp_layer的设计。
- `timescale 1ns / 1ps
- module udp_receive#(
- parameter LOCAL_PORT = 16'h0
- )(
- input clk ,
- input reset ,
-
- /*-------------ip_receive交互信号----------------*/
- input udp_rx_data_vld ,
- input udp_rx_data_last ,
- input [7 :0] udp_rx_data ,
- input [15:0] udp_rx_length ,
-
- /*-----------------用户端接受信号------------------*/
- output reg app_rx_data_vld ,
- output reg app_rx_data_last ,
- output reg [7 :0] app_rx_data ,
- output reg [15:0] app_rx_length
- );
-
- reg [10:0] rx_cnt ;
- reg [15:0] rx_target_port ;
-
-
- /*------------------------------------------*\
- cnt
- \*------------------------------------------*/
- always @(posedge clk ) begin
- if(reset)
- rx_cnt <= 0;
- else if(udp_rx_data_vld)
- rx_cnt <= rx_cnt + 1 ;
- else
- rx_cnt <= 0;
- end
-
- always @(posedge clk ) begin
- if (rx_cnt == 2 || rx_cnt == 3)
- rx_target_port <= {rx_target_port[7:0],udp_rx_data};
- else
- rx_target_port <= rx_target_port;
- end
-
- always @(posedge clk ) begin
- if (rx_target_port == LOCAL_PORT && rx_cnt >= 8) begin
- app_rx_data_vld <= udp_rx_data_vld;
- app_rx_data_last<= udp_rx_data_last;
- app_rx_data <= udp_rx_data;
- app_rx_length <= udp_rx_length - 8;
- end
- else begin
- app_rx_data_vld <= 0;
- app_rx_data_last<= 0;
- app_rx_data <= 0;
- app_rx_length <= 0;
- end
- end
-
- endmodule
udp_send模块
- `timescale 1ns / 1ps
-
- module udp_send #(
- parameter LOCAL_PORT = 16'h0 ,
- parameter TARGET_PORT = 16'h0
-
- )(
- input clk,
- input reset,
-
- /*-------ip_send块交互的信号--------------------*/
- output reg udp_tx_data_vld ,
- output reg udp_tx_data_last ,
- output reg [7:0] udp_tx_data ,
- output reg [15:0] udp_tx_length ,
-
- /*----------------用户发送端信号 ----------------*/
- input app_tx_data_vld ,
- input app_tx_data_last ,
- input [7:0] app_tx_data ,
- input [15:0] app_tx_length ,
- output app_tx_req ,
- output reg app_tx_ready
- );
-
-
- localparam READY_CNT_MAX = 35;
- reg [7:0] ready_cnt ;
- reg app_tx_data_vld_r ;
- reg app_tx_data_last_r ;
- reg [7:0] app_tx_data_r ;
- reg [15:0] app_tx_length_r ;
- reg [15:0] app_length ;
- reg [10:0] tx_cnt ;
- wire [7:0] app_tx_data_delay ;
-
- assign app_tx_req = app_tx_data_vld;
- /*------------------------------------------*\
- 打拍
- \*------------------------------------------*/
- always @(posedge clk) begin
- app_tx_data_vld_r <= app_tx_data_vld;
- app_tx_data_last_r <= app_tx_data_last;
- app_tx_length_r <= app_tx_length;
- app_tx_data_r <= app_tx_data;
- end
-
- always @(posedge clk) begin
- if (app_tx_data_vld_r)
- app_length <= app_tx_length_r;
- else
- app_length <= app_length;
- end
-
- /*------------------------------------------*\
- tx_cnt
- \*------------------------------------------*/
- always @(posedge clk) begin
- if (reset)
- tx_cnt <= 0;
- else if (app_length < 18 && tx_cnt == 25) //数据最小帧长为18byte
- tx_cnt <= 0;
- else if (app_length >= 18 && tx_cnt == app_length + 7)
- tx_cnt <= 0;
- else if (app_tx_data_vld_r || tx_cnt != 0)
- tx_cnt <= tx_cnt + 1;
- else
- tx_cnt <= tx_cnt;
- end
-
- /*------------------------------------------*\
- 组包
- \*------------------------------------------*/
-
- always @(posedge clk) begin
- if (reset)
- udp_tx_data <= 0;
- else begin
- case(tx_cnt)
- 0 : udp_tx_data <= LOCAL_PORT[15:8];
- 1 : udp_tx_data <= LOCAL_PORT[7:0];
-
- 2 : udp_tx_data <= TARGET_PORT[15:8];
- 3 : udp_tx_data <= TARGET_PORT[7:0];
-
- 4 : udp_tx_data <= udp_tx_length[15:8];
- 5 : udp_tx_data <= udp_tx_length[7:0];
-
- 6 : udp_tx_data <= 0;
- 7 : udp_tx_data <= 0;
-
- default : udp_tx_data <= app_tx_data_delay;
- endcase
- end
- end
-
- always @(posedge clk) begin
- if (app_length <= 18)
- udp_tx_length <= 26;
- else if (app_length > 18)
- udp_tx_length <= app_length + 8;
- else
- udp_tx_length <= udp_tx_length;
- end
-
- always @(posedge clk) begin
- if (reset)
- udp_tx_data_vld <= 0;
- else if (udp_tx_data_last)
- udp_tx_data_vld <= 0;
- else if (app_tx_data_vld_r)
- udp_tx_data_vld <= 1;
- else
- udp_tx_data_vld <= udp_tx_data_vld;
- end
-
- always @(posedge clk) begin
- if (reset)
- udp_tx_data_last <= 0;
- else if (app_length < 18 && tx_cnt == 25)
- udp_tx_data_last <= 1'b1;
- else if (app_length >= 18 && tx_cnt == app_length + 7)
- udp_tx_data_last <= 1'b1;
- else
- udp_tx_data_last <= 0;
-
- end
-
- /*------------------------------------------*\
- ready
- \*------------------------------------------*/
- always @(posedge clk) begin
- if (reset)
- ready_cnt <= 0;
- else if (ready_cnt == READY_CNT_MAX)
- ready_cnt <= 0;
- else if (app_tx_data_last_r || ready_cnt != 0)
- ready_cnt <= ready_cnt + 1;
- else
- ready_cnt <= ready_cnt;
- end
-
- always @(posedge clk) begin
- if (reset)
- app_tx_ready <= 1'b1;
- else if (ready_cnt != 0)
- app_tx_ready <= 0;
- else
- app_tx_ready <= 1'b1;
- end
-
- /*------------------------------------------*\
- 打拍
- \*------------------------------------------*/
- //注意 : 如果A的值为7,udp_tx_data_delay打拍为8拍
- c_shift_ram_0 ip_delay (
- .A(7), // input wire [5 : 0] A
- .D(app_tx_data_r), // input wire [7 : 0] D
- .CLK(clk), // input wire CLK
- .Q(app_tx_data_delay) // output wire [7 : 0] Q
- );
-
- endmodule
udp层分别实现了接收和发送两部分,将两部分例化封装顶层udp_layer:
- `timescale 1ns / 1ps
-
- module udp_layer #(
- parameter LOCAL_PORT = 16'h0 ,
- parameter TARGET_PORT = 16'h0
- )(
- input app_tx_clk ,
- input app_rx_clk ,
-
- input app_tx_reset ,
- input app_rx_reset ,
-
- input udp_rx_data_vld ,
- input udp_rx_data_last ,
- input [7:0] udp_rx_data ,
- input [15:0] udp_rx_length ,
-
- output udp_tx_data_vld ,
- output udp_tx_data_last ,
- output [7:0] udp_tx_data ,
- output [15:0] udp_tx_length ,
-
- output app_rx_data_vld ,
- output app_rx_data_last ,
- output [7:0] app_rx_data ,
- output [15:0] app_rx_length ,
-
- input app_tx_data_vld ,
- input app_tx_data_last ,
- input [7:0] app_tx_data ,
- input [15:0] app_tx_length ,
- output app_tx_req ,
- output app_tx_ready
-
- );
-
- udp_receive #(
- .LOCAL_PORT(LOCAL_PORT)
- ) udp_receive (
- .clk (app_rx_clk),
- .reset (app_rx_reset),
-
- .udp_rx_data_vld (udp_rx_data_vld),
- .udp_rx_data_last (udp_rx_data_last),
- .udp_rx_data (udp_rx_data),
- .udp_rx_length (udp_rx_length),
-
- .app_rx_data_vld (app_rx_data_vld),
- .app_rx_data_last (app_rx_data_last),
- .app_rx_data (app_rx_data),
- .app_rx_length (app_rx_length)
- );
-
-
- udp_send #(
- .LOCAL_PORT(LOCAL_PORT),
- .TARGET_PORT(TARGET_PORT)
- ) udp_send (
- .clk (app_tx_clk),
- .reset (app_tx_reset),
-
- .udp_tx_data_vld (udp_tx_data_vld),
- .udp_tx_data_last (udp_tx_data_last),
- .udp_tx_data (udp_tx_data),
- .udp_tx_length (udp_tx_length),
-
- .app_tx_data_vld (app_tx_data_vld),
- .app_tx_data_last (app_tx_data_last),
- .app_tx_data (app_tx_data),
- .app_tx_length (app_tx_length),
- .app_tx_req (app_tx_req),
- .app_tx_ready (app_tx_ready)
- );
-
-
- endmodule
至此,我们完成了UDP层的发送与接受。同时,也已经了解了UDP协议首部的具体内容。
接下来,在下一篇博客中将会实现以太网UDP通信的顶层设计。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。