当前位置:   article > 正文

FPGA - 以太网UDP通信(四)

FPGA - 以太网UDP通信(四)

 一,引言


前文链接:FPGA - 以太网UDP通信(一)

                  FPGA - 以太网UDP通信(二)

                  FPGA - 以太网UDP通信(三)

在以上文章中介绍了以太网简介,以太网UDP通信硬件结构,以及PHY芯片RGMII接口-GMII接口转换逻辑,以及数据链路层(MAC层)接受发送逻辑,IP层接受发送逻辑。接下来介绍UDP层接收发送逻辑。

二,以太网UDP通信结构框图

在之前文章中已经介绍了UDP通信结构框图,如下:

三,UDP层数据帧

UDP(User Datagram Protocol),用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP提供了无连接通信,且不对传送数据包进行可靠性保证,适合于一次传输少量数据,UDP传输的可靠性由应用层负责。

UDP报文没有可靠性保证顺序保证流量控制字段等,可靠性较差。但是正因为UDP协议的控制选项较少,在数据传输过程中延迟小数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如DNS、TFTP、SNMP等。 UDP在IP报文中的位置如下图所示:

UDP的报文格式

UDP首部有8个字节,由4个字段构成,每个字段都是两个字节。

------------------------------------------------------------UDP首部---------------------------------------------------------

源端口       源端口号,需要对方回信时选用,不需要时全部置0。

目的端口  目的端口号,在终点交付报文的时候需要用到。

长度         UDP的数据报的长度(包括首部和数据)其最小值为8字节(只有首部),最大值为65535字节。

校验和      检测UDP数据报在传输中是否有错,有错则丢弃。
该字段是可选的,当源主机不想计算校验和,则直接令该字段全为0。

---------------------------------------------------------------------------------------------------------------------------------

四,UDP层代码设计

UDP层的接受和发送逻辑和mac层以及IP层的接受发送逻辑类似,和之前一样只需要在udp_receive中要完成数据解包校验,在udp_send中要完成数据组包,就完成了整个udp_layer的设计。

udp_receive模块模块

  1. `timescale 1ns / 1ps
  2. module udp_receive#(
  3. parameter LOCAL_PORT = 16'h0
  4. )(
  5. input clk ,
  6. input reset ,
  7. /*-------------ip_receive交互信号----------------*/
  8. input udp_rx_data_vld ,
  9. input udp_rx_data_last ,
  10. input [7 :0] udp_rx_data ,
  11. input [15:0] udp_rx_length ,
  12. /*-----------------用户端接受信号------------------*/
  13. output reg app_rx_data_vld ,
  14. output reg app_rx_data_last ,
  15. output reg [7 :0] app_rx_data ,
  16. output reg [15:0] app_rx_length
  17. );
  18. reg [10:0] rx_cnt ;
  19. reg [15:0] rx_target_port ;
  20. /*------------------------------------------*\
  21. cnt
  22. \*------------------------------------------*/
  23. always @(posedge clk ) begin
  24. if(reset)
  25. rx_cnt <= 0;
  26. else if(udp_rx_data_vld)
  27. rx_cnt <= rx_cnt + 1 ;
  28. else
  29. rx_cnt <= 0;
  30. end
  31. always @(posedge clk ) begin
  32. if (rx_cnt == 2 || rx_cnt == 3)
  33. rx_target_port <= {rx_target_port[7:0],udp_rx_data};
  34. else
  35. rx_target_port <= rx_target_port;
  36. end
  37. always @(posedge clk ) begin
  38. if (rx_target_port == LOCAL_PORT && rx_cnt >= 8) begin
  39. app_rx_data_vld <= udp_rx_data_vld;
  40. app_rx_data_last<= udp_rx_data_last;
  41. app_rx_data <= udp_rx_data;
  42. app_rx_length <= udp_rx_length - 8;
  43. end
  44. else begin
  45. app_rx_data_vld <= 0;
  46. app_rx_data_last<= 0;
  47. app_rx_data <= 0;
  48. app_rx_length <= 0;
  49. end
  50. end
  51. endmodule

udp_send模块

  1. `timescale 1ns / 1ps
  2. module udp_send #(
  3. parameter LOCAL_PORT = 16'h0 ,
  4. parameter TARGET_PORT = 16'h0
  5. )(
  6. input clk,
  7. input reset,
  8. /*-------ip_send块交互的信号--------------------*/
  9. output reg udp_tx_data_vld ,
  10. output reg udp_tx_data_last ,
  11. output reg [7:0] udp_tx_data ,
  12. output reg [15:0] udp_tx_length ,
  13. /*----------------用户发送端信号 ----------------*/
  14. input app_tx_data_vld ,
  15. input app_tx_data_last ,
  16. input [7:0] app_tx_data ,
  17. input [15:0] app_tx_length ,
  18. output app_tx_req ,
  19. output reg app_tx_ready
  20. );
  21. localparam READY_CNT_MAX = 35;
  22. reg [7:0] ready_cnt ;
  23. reg app_tx_data_vld_r ;
  24. reg app_tx_data_last_r ;
  25. reg [7:0] app_tx_data_r ;
  26. reg [15:0] app_tx_length_r ;
  27. reg [15:0] app_length ;
  28. reg [10:0] tx_cnt ;
  29. wire [7:0] app_tx_data_delay ;
  30. assign app_tx_req = app_tx_data_vld;
  31. /*------------------------------------------*\
  32. 打拍
  33. \*------------------------------------------*/
  34. always @(posedge clk) begin
  35. app_tx_data_vld_r <= app_tx_data_vld;
  36. app_tx_data_last_r <= app_tx_data_last;
  37. app_tx_length_r <= app_tx_length;
  38. app_tx_data_r <= app_tx_data;
  39. end
  40. always @(posedge clk) begin
  41. if (app_tx_data_vld_r)
  42. app_length <= app_tx_length_r;
  43. else
  44. app_length <= app_length;
  45. end
  46. /*------------------------------------------*\
  47. tx_cnt
  48. \*------------------------------------------*/
  49. always @(posedge clk) begin
  50. if (reset)
  51. tx_cnt <= 0;
  52. else if (app_length < 18 && tx_cnt == 25) //数据最小帧长为18byte
  53. tx_cnt <= 0;
  54. else if (app_length >= 18 && tx_cnt == app_length + 7)
  55. tx_cnt <= 0;
  56. else if (app_tx_data_vld_r || tx_cnt != 0)
  57. tx_cnt <= tx_cnt + 1;
  58. else
  59. tx_cnt <= tx_cnt;
  60. end
  61. /*------------------------------------------*\
  62. 组包
  63. \*------------------------------------------*/
  64. always @(posedge clk) begin
  65. if (reset)
  66. udp_tx_data <= 0;
  67. else begin
  68. case(tx_cnt)
  69. 0 : udp_tx_data <= LOCAL_PORT[15:8];
  70. 1 : udp_tx_data <= LOCAL_PORT[7:0];
  71. 2 : udp_tx_data <= TARGET_PORT[15:8];
  72. 3 : udp_tx_data <= TARGET_PORT[7:0];
  73. 4 : udp_tx_data <= udp_tx_length[15:8];
  74. 5 : udp_tx_data <= udp_tx_length[7:0];
  75. 6 : udp_tx_data <= 0;
  76. 7 : udp_tx_data <= 0;
  77. default : udp_tx_data <= app_tx_data_delay;
  78. endcase
  79. end
  80. end
  81. always @(posedge clk) begin
  82. if (app_length <= 18)
  83. udp_tx_length <= 26;
  84. else if (app_length > 18)
  85. udp_tx_length <= app_length + 8;
  86. else
  87. udp_tx_length <= udp_tx_length;
  88. end
  89. always @(posedge clk) begin
  90. if (reset)
  91. udp_tx_data_vld <= 0;
  92. else if (udp_tx_data_last)
  93. udp_tx_data_vld <= 0;
  94. else if (app_tx_data_vld_r)
  95. udp_tx_data_vld <= 1;
  96. else
  97. udp_tx_data_vld <= udp_tx_data_vld;
  98. end
  99. always @(posedge clk) begin
  100. if (reset)
  101. udp_tx_data_last <= 0;
  102. else if (app_length < 18 && tx_cnt == 25)
  103. udp_tx_data_last <= 1'b1;
  104. else if (app_length >= 18 && tx_cnt == app_length + 7)
  105. udp_tx_data_last <= 1'b1;
  106. else
  107. udp_tx_data_last <= 0;
  108. end
  109. /*------------------------------------------*\
  110. ready
  111. \*------------------------------------------*/
  112. always @(posedge clk) begin
  113. if (reset)
  114. ready_cnt <= 0;
  115. else if (ready_cnt == READY_CNT_MAX)
  116. ready_cnt <= 0;
  117. else if (app_tx_data_last_r || ready_cnt != 0)
  118. ready_cnt <= ready_cnt + 1;
  119. else
  120. ready_cnt <= ready_cnt;
  121. end
  122. always @(posedge clk) begin
  123. if (reset)
  124. app_tx_ready <= 1'b1;
  125. else if (ready_cnt != 0)
  126. app_tx_ready <= 0;
  127. else
  128. app_tx_ready <= 1'b1;
  129. end
  130. /*------------------------------------------*\
  131. 打拍
  132. \*------------------------------------------*/
  133. //注意 : 如果A的值为7,udp_tx_data_delay打拍为8
  134. c_shift_ram_0 ip_delay (
  135. .A(7), // input wire [5 : 0] A
  136. .D(app_tx_data_r), // input wire [7 : 0] D
  137. .CLK(clk), // input wire CLK
  138. .Q(app_tx_data_delay) // output wire [7 : 0] Q
  139. );
  140. endmodule

 

顶层设计

udp层分别实现了接收和发送两部分,将两部分例化封装顶层udp_layer

  1. `timescale 1ns / 1ps
  2. module udp_layer #(
  3. parameter LOCAL_PORT = 16'h0 ,
  4. parameter TARGET_PORT = 16'h0
  5. )(
  6. input app_tx_clk ,
  7. input app_rx_clk ,
  8. input app_tx_reset ,
  9. input app_rx_reset ,
  10. input udp_rx_data_vld ,
  11. input udp_rx_data_last ,
  12. input [7:0] udp_rx_data ,
  13. input [15:0] udp_rx_length ,
  14. output udp_tx_data_vld ,
  15. output udp_tx_data_last ,
  16. output [7:0] udp_tx_data ,
  17. output [15:0] udp_tx_length ,
  18. output app_rx_data_vld ,
  19. output app_rx_data_last ,
  20. output [7:0] app_rx_data ,
  21. output [15:0] app_rx_length ,
  22. input app_tx_data_vld ,
  23. input app_tx_data_last ,
  24. input [7:0] app_tx_data ,
  25. input [15:0] app_tx_length ,
  26. output app_tx_req ,
  27. output app_tx_ready
  28. );
  29. udp_receive #(
  30. .LOCAL_PORT(LOCAL_PORT)
  31. ) udp_receive (
  32. .clk (app_rx_clk),
  33. .reset (app_rx_reset),
  34. .udp_rx_data_vld (udp_rx_data_vld),
  35. .udp_rx_data_last (udp_rx_data_last),
  36. .udp_rx_data (udp_rx_data),
  37. .udp_rx_length (udp_rx_length),
  38. .app_rx_data_vld (app_rx_data_vld),
  39. .app_rx_data_last (app_rx_data_last),
  40. .app_rx_data (app_rx_data),
  41. .app_rx_length (app_rx_length)
  42. );
  43. udp_send #(
  44. .LOCAL_PORT(LOCAL_PORT),
  45. .TARGET_PORT(TARGET_PORT)
  46. ) udp_send (
  47. .clk (app_tx_clk),
  48. .reset (app_tx_reset),
  49. .udp_tx_data_vld (udp_tx_data_vld),
  50. .udp_tx_data_last (udp_tx_data_last),
  51. .udp_tx_data (udp_tx_data),
  52. .udp_tx_length (udp_tx_length),
  53. .app_tx_data_vld (app_tx_data_vld),
  54. .app_tx_data_last (app_tx_data_last),
  55. .app_tx_data (app_tx_data),
  56. .app_tx_length (app_tx_length),
  57. .app_tx_req (app_tx_req),
  58. .app_tx_ready (app_tx_ready)
  59. );
  60. endmodule

五,总结

至此,我们完成了UDP层的发送与接受。同时,也已经了解了UDP协议首部的具体内容。

接下来,在下一篇博客中将会实现以太网UDP通信的顶层设计。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/420706
推荐阅读
相关标签
  

闽ICP备14008679号