当前位置:   article > 正文

FPGA - 以太网UDP通信(五)

FPGA - 以太网UDP通信(五)

一,引言


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

                  FPGA - 以太网UDP通信(二)

                  FPGA - 以太网UDP通信(三)

                  FPGA - 以太网UDP通信(四)​​​​​​

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

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

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

三,以太网UDP通信顶层设计

在之前文章中,我们已经完成了物理层(RGMII接口-GMII接口转换逻辑),数据链路层(MAC层接受发送逻辑),网络层(IP层接受发送逻辑),传输层(UDP层接受发送逻辑)。接下来将各层连接起来完成以太网UDP通信的顶层设计。

首先,我们将mac_layer,ip_layer,udp_layer例化udp_protocol_stack:

udp协议--udp_protocol_stack:

  1. `timescale 1ns / 1ps
  2. module udp_protocol_stack #(
  3. parameter LOCAL_MAC_ADDR = 48'hffffff_ffffff ,
  4. parameter TARGET_MAC_ADDR = 48'hffffff_ffffff ,
  5. parameter LOCAL_IP_ADDR = 32'h0 ,
  6. parameter TARGET_IP_ADDR = 32'h0 ,
  7. parameter LOCAL_PORT = 16'h0 ,
  8. parameter TARGET_PORT = 16'h0
  9. )(
  10. input phy_tx_clk ,
  11. input phy_rx_clk ,
  12. input reset ,
  13. /* ------------GMII接口信号--------------------------*/
  14. input gmii_rx_data_vld ,
  15. input [7:0] gmii_rx_data ,
  16. output gmii_tx_data_vld ,
  17. output [7:0] gmii_tx_data ,
  18. /* ------------用户接送端信号--------------------------*/
  19. input app_rx_clk ,
  20. output app_rx_data_vld ,
  21. output app_rx_data_last ,
  22. output [7:0] app_rx_data ,
  23. output [15:0] app_rx_length ,
  24. /*--------------用户发送端信号--------------------------*/
  25. input app_tx_clk ,
  26. input app_tx_data_vld ,
  27. input app_tx_data_last ,
  28. input [7:0] app_tx_data ,
  29. input [15:0] app_tx_length ,
  30. output app_tx_ready
  31. );
  32. wire app_tx_req ;
  33. wire mac_rx_data_vld ;
  34. wire mac_rx_data_last ;
  35. wire [7:0] mac_rx_data ;
  36. wire [15:0] mac_rx_frame_type ;
  37. wire mac_tx_data_vld ;
  38. wire mac_tx_data_last ;
  39. wire [7:0] mac_tx_data ;
  40. wire [15:0] mac_tx_frame_type ;
  41. wire [15:0] mac_tx_length ;
  42. wire ip_rx_data_vld ;
  43. wire ip_rx_data_last ;
  44. wire [7:0] ip_rx_data ;
  45. wire ip_tx_data_vld ;
  46. wire ip_tx_data_last ;
  47. wire [15:0] ip_tx_length ;
  48. wire [7:0 ] ip_tx_data ;
  49. wire udp_rx_data_vld ;
  50. wire udp_rx_data_last ;
  51. wire [7:0] udp_rx_data ;
  52. wire [15:0] udp_rx_length ;
  53. wire udp_tx_data_vld ;
  54. wire udp_tx_data_last ;
  55. wire [7:0] udp_tx_data ;
  56. wire [15:0] udp_tx_length ;
  57. wire icmp_rx_data_vld ;
  58. wire icmp_rx_data_last ;
  59. wire [7:0] icmp_rx_data ;
  60. wire [15:0] icmp_rx_length ;
  61. wire arp_rx_data_vld ;
  62. wire arp_rx_data_last ;
  63. wire [7:0] arp_rx_data ;
  64. /*---------------------------------------------------*\
  65. 复位信号处理
  66. \*---------------------------------------------------*/
  67. reg [19:0] phy_rx_reset_timer;
  68. reg phy_rx_reset_d0;
  69. reg phy_rx_reset_d1;
  70. reg phy_rx_reset ;
  71. always @(posedge phy_rx_clk or posedge reset) begin
  72. if (reset)
  73. phy_rx_reset_timer <= 0;
  74. else if (phy_rx_reset_timer <= 20'h000ff)
  75. phy_rx_reset_timer <= phy_rx_reset_timer + 1;
  76. else
  77. phy_rx_reset_timer <= phy_rx_reset_timer;
  78. end
  79. always @(posedge phy_rx_clk or posedge reset) begin
  80. if (reset) begin
  81. phy_rx_reset_d0 <= 1'b1;
  82. phy_rx_reset_d1 <= 1'b1;
  83. phy_rx_reset <= 1'b1;
  84. end
  85. else begin
  86. phy_rx_reset_d0 <= phy_rx_reset_timer <= 20'h000ff;
  87. phy_rx_reset_d1 <= phy_rx_reset_d0;
  88. phy_rx_reset <= phy_rx_reset_d1;
  89. end
  90. end
  91. //---------------------------------------------------------------------------
  92. reg [19:0] phy_tx_reset_timer;
  93. reg phy_tx_reset_d0;
  94. reg phy_tx_reset_d1;
  95. reg phy_tx_reset ;
  96. always @(posedge phy_tx_clk or posedge reset) begin
  97. if (reset)
  98. phy_tx_reset_timer <= 0;
  99. else if (phy_tx_reset_timer <= 20'h000ff)
  100. phy_tx_reset_timer <= phy_tx_reset_timer + 1;
  101. else
  102. phy_tx_reset_timer <= phy_tx_reset_timer;
  103. end
  104. always @(posedge phy_tx_clk or posedge reset) begin
  105. if (reset) begin
  106. phy_tx_reset_d0 <= 1'b1;
  107. phy_tx_reset_d1 <= 1'b1;
  108. phy_tx_reset <= 1'b1;
  109. end
  110. else begin
  111. phy_tx_reset_d0 <= phy_tx_reset_timer <= 20'h000ff;
  112. phy_tx_reset_d1 <= phy_tx_reset_d0;
  113. phy_tx_reset <= phy_tx_reset_d1;
  114. end
  115. end
  116. //---------------------------------------------------------------------------
  117. reg [19:0] app_tx_reset_timer;
  118. reg app_tx_reset_d0;
  119. reg app_tx_reset_d1;
  120. reg app_tx_reset ;
  121. always @(posedge app_tx_clk or posedge reset) begin
  122. if (reset)
  123. app_tx_reset_timer <= 0;
  124. else if (app_tx_reset_timer <= 20'h000ff)
  125. app_tx_reset_timer <= app_tx_reset_timer + 1;
  126. else
  127. app_tx_reset_timer <= app_tx_reset_timer;
  128. end
  129. always @(posedge app_tx_clk or posedge reset) begin
  130. if (reset) begin
  131. app_tx_reset_d0 <= 1'b1;
  132. app_tx_reset_d1 <= 1'b1;
  133. app_tx_reset <= 1'b1;
  134. end
  135. else begin
  136. app_tx_reset_d0 <= app_tx_reset_timer <= 20'h000ff;
  137. app_tx_reset_d1 <= app_tx_reset_d0;
  138. app_tx_reset <= app_tx_reset_d1;
  139. end
  140. end
  141. //---------------------------------------------------------------------------
  142. reg [19:0] app_rx_reset_timer;
  143. reg app_rx_reset_d0;
  144. reg app_rx_reset_d1;
  145. reg app_rx_reset ;
  146. always @(posedge app_rx_clk or posedge reset) begin
  147. if (reset)
  148. app_rx_reset_timer <= 0;
  149. else if (app_rx_reset_timer <= 20'h000ff)
  150. app_rx_reset_timer <= app_rx_reset_timer + 1;
  151. else
  152. app_rx_reset_timer <= app_rx_reset_timer;
  153. end
  154. always @(posedge app_rx_clk or posedge reset) begin
  155. if (reset) begin
  156. app_rx_reset_d0 <= 1'b1;
  157. app_rx_reset_d1 <= 1'b1;
  158. app_rx_reset <= 1'b1;
  159. end
  160. else begin
  161. app_rx_reset_d0 <= app_rx_reset_timer <= 20'h000ff;
  162. app_rx_reset_d1 <= app_rx_reset_d0;
  163. app_rx_reset <= app_rx_reset_d1;
  164. end
  165. end
  166. /*---------------------------------------------------*\
  167. 模块例化
  168. \*---------------------------------------------------*/
  169. mac_layer #(
  170. .LOCAL_MAC_ADDR(LOCAL_MAC_ADDR),
  171. .TARGET_MAC_ADDR(TARGET_MAC_ADDR),
  172. .CRC_CHACK_EN(1)
  173. ) mac_layer (
  174. .app_tx_clk (app_tx_clk),
  175. .app_rx_clk (app_rx_clk),
  176. .phy_tx_clk (phy_tx_clk),
  177. .phy_rx_clk (phy_rx_clk),
  178. .app_tx_reset (app_tx_reset),
  179. .app_rx_reset (app_rx_reset),
  180. .phy_tx_reset (phy_tx_reset),
  181. .phy_rx_reset (phy_rx_reset),
  182. .gmii_rx_data_vld (gmii_rx_data_vld),
  183. .gmii_rx_data (gmii_rx_data),
  184. .gmii_tx_data_vld (gmii_tx_data_vld),
  185. .gmii_tx_data (gmii_tx_data),
  186. .mac_rx_data_vld (mac_rx_data_vld),
  187. .mac_rx_data_last (mac_rx_data_last),
  188. .mac_rx_data (mac_rx_data),
  189. .mac_rx_frame_type (mac_rx_frame_type),
  190. .mac_tx_data_vld (ip_tx_data_vld),
  191. .mac_tx_data_last (ip_tx_data_last),
  192. .mac_tx_data (ip_tx_data),
  193. .mac_tx_frame_type (16'h0800 ), //ip层
  194. .mac_tx_length (ip_tx_length)
  195. );
  196. mac_to_ip_arp mac_to_ip_arp
  197. (
  198. .clk (app_rx_clk),
  199. .reset (app_rx_reset),
  200. .mac_rx_data_vld (mac_rx_data_vld),
  201. .mac_rx_data_last (mac_rx_data_last),
  202. .mac_rx_data (mac_rx_data),
  203. .mac_rx_frame_type (mac_rx_frame_type),
  204. .ip_rx_data_vld (ip_rx_data_vld),
  205. .ip_rx_data_last (ip_rx_data_last),
  206. .ip_rx_data (ip_rx_data),
  207. .arp_rx_data_vld (arp_rx_data_vld),
  208. .arp_rx_data_last (arp_rx_data_last),
  209. .arp_rx_data (arp_rx_data)
  210. );
  211. ip_layer #(
  212. .LOCAL_IP_ADDR(LOCAL_IP_ADDR),
  213. .TARGET_IP_ADDR(TARGET_IP_ADDR)
  214. ) ip_layer (
  215. .app_tx_clk (app_tx_clk),
  216. .app_rx_clk (app_rx_clk),
  217. .app_rx_reset (app_rx_reset),
  218. .app_tx_reset (app_tx_reset),
  219. .ip_rx_data_vld (ip_rx_data_vld),
  220. .ip_rx_data_last (ip_rx_data_last),
  221. .ip_rx_data (ip_rx_data),
  222. .ip_tx_data_vld (ip_tx_data_vld),
  223. .ip_tx_data_last (ip_tx_data_last),
  224. .ip_tx_length (ip_tx_length),
  225. .ip_tx_data (ip_tx_data),
  226. .udp_rx_data_vld (udp_rx_data_vld),
  227. .udp_rx_data_last (udp_rx_data_last),
  228. .udp_rx_data (udp_rx_data),
  229. .udp_rx_length (udp_rx_length),
  230. .udp_tx_data_vld (udp_tx_data_vld),
  231. .udp_tx_data_last (udp_tx_data_last),
  232. .udp_tx_data (udp_tx_data),
  233. .udp_tx_length (udp_tx_length),
  234. .icmp_rx_data_vld (icmp_rx_data_vld),
  235. .icmp_rx_data_last (icmp_rx_data_last),
  236. .icmp_rx_data (icmp_rx_data),
  237. .icmp_rx_length (icmp_rx_length)
  238. );
  239. udp_layer #(
  240. .LOCAL_PORT(LOCAL_PORT),
  241. .TARGET_PORT(TARGET_PORT)
  242. ) udp_layer (
  243. .app_tx_clk (app_tx_clk),
  244. .app_rx_clk (app_rx_clk),
  245. .app_tx_reset (app_tx_reset),
  246. .app_rx_reset (app_rx_reset),
  247. .udp_rx_data_vld (udp_rx_data_vld),
  248. .udp_rx_data_last (udp_rx_data_last),
  249. .udp_rx_data (udp_rx_data),
  250. .udp_rx_length (udp_rx_length),
  251. .udp_tx_data_vld (udp_tx_data_vld),
  252. .udp_tx_data_last (udp_tx_data_last),
  253. .udp_tx_data (udp_tx_data),
  254. .udp_tx_length (udp_tx_length),
  255. .app_rx_data_vld (app_rx_data_vld),
  256. .app_rx_data_last (app_rx_data_last),
  257. .app_rx_data (app_rx_data),
  258. .app_rx_length (app_rx_length),
  259. .app_tx_data_vld (app_tx_data_vld),
  260. .app_tx_data_last (app_tx_data_last),
  261. .app_tx_data (app_tx_data),
  262. .app_tx_length (app_tx_length),
  263. .app_tx_req (app_tx_req),
  264. .app_tx_ready (app_tx_ready)
  265. );
  266. endmodule

在上述代码中为什么要对复位信号处理呢,因为输入的复位并不能保证在这四个时钟(app_tx_clk,app_rx_clk,phy_tx_clk,phy_rx_clk)下的。所以复位信号在分别在这4个时钟域下进行打拍,就可以分别得到这4个时钟域下复位信号。

顶层设计

根据udp_protocol_stack和rgmii_interface(FPGA - 以太网UDP通信(一)中)·将两部分例化封装顶层top

  1. `timescale 1ns / 1ps
  2. module top(
  3. input wire clkin_50m ,
  4. input phy_rgmii_rx_clk_i ,
  5. input phy_rgmii_rx_ctl ,
  6. input [3:0] phy_rgmii_rx_data ,
  7. output phy_rgmii_tx_clk ,
  8. output phy_rgmii_tx_ctl ,
  9. output [3:0] phy_rgmii_tx_data ,
  10. output phy_reset
  11. );
  12. parameter LOCAL_MAC_ADDR = {8'd0,8'd1,8'd2,8'd3,8'd4,8'd5};
  13. parameter TARGET_MAC_ADDR = {8'd0,8'd1,8'd2,8'd3,8'd4,8'd5};
  14. parameter LOCAL_IP_ADDR = {8'd0,8'd1,8'd2,8'd3};
  15. parameter TARGET_IP_ADDR = {8'd0,8'd1,8'd2,8'd3};
  16. parameter LOCAL_PORT = 16'h8060;
  17. parameter TARGET_PORT = 16'h8060;
  18. wire reset;
  19. wire clkout_125m;
  20. wire clkout_200m;
  21. wire delay_refclk;
  22. wire phy_tx_clk;
  23. wire phy_rx_clk;
  24. wire app_rx_clk;
  25. wire app_tx_clk;
  26. wire gmii_rx_vld;
  27. wire gmii_rx_error;
  28. wire [7:0] gmii_rx_data;
  29. wire gmii_tx_vld;
  30. wire [7:0] gmii_tx_data;
  31. wire app_rx_data_vld;
  32. wire app_rx_data_last;
  33. wire [7:0] app_rx_data;
  34. wire [15:0] app_rx_length;
  35. wire app_tx_data_vld;
  36. wire app_tx_data_last;
  37. wire [7:0] app_tx_data;
  38. wire [15:0] app_tx_length;
  39. wire app_tx_ready;
  40. wire phy_rgmii_rx_clk;
  41. wire pll_locked;
  42. /*------------------------------------------*\
  43. clk and reset
  44. \*------------------------------------------*/
  45. clk_wiz_1 instance_name
  46. (
  47. // Clock out ports
  48. .clk_out1(phy_rgmii_rx_clk), // output clk_out1
  49. // Status and control signals
  50. .locked(pll_locked), // output locked
  51. // Clock in ports
  52. .clk_in1(phy_rgmii_rx_clk_i)); // input clk_in1
  53. assign delay_refclk = clkout_200m;
  54. assign phy_tx_clk = clkout_125m;
  55. assign app_rx_clk = clkout_200m;
  56. assign app_tx_clk = clkout_200m;
  57. assign phy_reset = ~reset;
  58. /*------------------------------------------*\
  59. 模块例化
  60. \*------------------------------------------*/
  61. clock_and_reset clock_and_reset (
  62. .clkin_50m (clkin_50m),
  63. .clkout_125m (clkout_125m),
  64. .clkout_200m (clkout_200m),
  65. .reset (reset)
  66. );
  67. rgmii_interface rgmii_interface(
  68. .reset (reset),
  69. .delay_refclk (delay_refclk),
  70. .phy_rgmii_rx_clk (phy_rgmii_rx_clk),
  71. .phy_rgmii_rx_ctl (phy_rgmii_rx_ctl),
  72. .phy_rgmii_rx_data (phy_rgmii_rx_data),
  73. .phy_rgmii_tx_clk (phy_rgmii_tx_clk),
  74. .phy_rgmii_tx_ctl (phy_rgmii_tx_ctl),
  75. .phy_rgmii_tx_data (phy_rgmii_tx_data),
  76. .gmii_rx_clk (phy_rx_clk), //rgmii_interface输出的gmii_rx_clk
  77. .gmii_rx_vld (gmii_rx_vld),
  78. .gmii_rx_error (gmii_rx_error),
  79. .gmii_rx_data (gmii_rx_data),
  80. .gmii_tx_clk (phy_tx_clk),
  81. .gmii_tx_vld (gmii_tx_vld),
  82. .gmii_tx_data (gmii_tx_data)
  83. );
  84. udp_protocol_stack #(
  85. .LOCAL_MAC_ADDR (LOCAL_MAC_ADDR),
  86. .TARGET_MAC_ADDR (TARGET_MAC_ADDR),
  87. .LOCAL_IP_ADDR (LOCAL_IP_ADDR),
  88. .TARGET_IP_ADDR (TARGET_IP_ADDR),
  89. .LOCAL_PORT (LOCAL_PORT),
  90. .TARGET_PORT (TARGET_PORT)
  91. ) udp_protocol_stack (
  92. .phy_tx_clk (phy_tx_clk),
  93. .phy_rx_clk (phy_rx_clk),
  94. .reset (reset),
  95. .gmii_rx_data_vld (gmii_rx_vld),
  96. .gmii_rx_data (gmii_rx_data),
  97. .gmii_tx_data_vld (gmii_tx_vld),
  98. .gmii_tx_data (gmii_tx_data),
  99. .app_rx_clk (app_rx_clk),
  100. .app_rx_data_vld (app_rx_data_vld),
  101. .app_rx_data_last (app_rx_data_last),
  102. .app_rx_data (app_rx_data),
  103. .app_rx_length (app_rx_length),
  104. .app_tx_clk (app_tx_clk),
  105. .app_tx_data_vld (app_tx_data_vld),
  106. .app_tx_data_last (app_tx_data_last),
  107. .app_tx_data (app_tx_data),
  108. .app_tx_length (app_tx_length),
  109. .app_tx_ready (app_tx_ready)
  110. );
  111. /*------------------------------------------*\
  112. 上板回环
  113. \*------------------------------------------*/
  114. c_shift_ram_0 top_delay_1 (
  115. .A(60), // input wire [5 : 0] A
  116. .D({app_rx_data_vld,app_rx_data_last,6'd0}), // input wire [7 : 0] D
  117. .CLK(clkout_200m), // input wire CLK
  118. .Q({app_tx_data_vld,app_tx_data_last,6'd0}) // output wire [7 : 0] Q
  119. );
  120. c_shift_ram_0 top_delay_2 (
  121. .A(60), // input wire [5 : 0] A
  122. .D(app_rx_data), // input wire [7 : 0] D
  123. .CLK(clkout_200m), // input wire CLK
  124. .Q(app_tx_data) // output wire [7 : 0] Q
  125. );
  126. c_shift_ram_1 top_delay_3 (
  127. .A(60), // input wire [5 : 0] A
  128. .D(app_rx_length), // input wire [15 : 0] D
  129. .CLK(clkout_200m), // input wire CLK
  130. .Q(app_tx_length) // output wire [15 : 0] Q
  131. );
  132. endmodule

注意我在这里也调试了好久) :PHY芯片的时钟(phy_rgmii_rx_clk_i)是外部时钟,将外部时钟信号不加处理直接引入FPGA芯片使用,有时候会导致意想不到的BUG发生,而且这种BUG是不可重复的。

将外部时钟直接连接到FPGA芯片普通I/O管脚,而非专用时钟输入管脚,将会导致下面问题
1.由于该时钟信号是通过各种长短布线资源,甚至经过LUT连接才能到达其驱动的各个寄存器,因此该时钟信号从进入FPGA管脚,到传递到各个寄存器的时钟输入端,其时间是很难保持相同的,距离的远近直接决定了该时钟信号的传输延迟(时钟延迟)。而这个传输延迟的差值,可能达到几纳秒甚至十几纳秒。这个差值,将直接影响数据的建立保持时间,造成时序无法收敛,从而导致设计失败。
2.使用非全局布线资源,时钟信号在布线的过程中更容易受到周围信号的干扰。导致时钟质量变差。什么意思呢?打个比方,一只小鸟和一只兔子共同穿越一个满是灰尘的工地。工地上到处都是灰尘。小鸟从空中飞过,不直接与灰尘接触,因此基本不会沾到灰尘,因为它有自己独立的路线和空间。而兔子因为不会飞,因此只能跑着从工地中穿过,那么,不可避免的,兔子的脚上会沾上灰尘。导致当兔子穿过这个工地的时候,早已由小白兔变成了小灰兔。时钟信号也是如此,全局时钟资源有专门的时钟路径,在自己的空间走线,不穿过或很少穿过各种高速翻转的逻辑区域,因此很少受到污染。而非全局时钟资源没有专门的时钟路径,只能使用通用布线资源,而这些布线不可避免的会穿过很多高速翻转的逻辑区域。从而受到这些逻辑的翻转噪声的污染。最终时钟信号变的很差。例如边沿上升和下降更慢,占空比发生变化,时钟抖动增大等。

所以,在这里我把PHY芯片的时钟(phy_rgmii_rx_clk_i)引入到PLL中,输入(phy_rgmii_rx_clk_i)125Mhz 输出(phy_rgmii_rx_clk)125Mhz,并将其相位设置为90,延时一下,使其更稳定,这样就保证了外部输入时钟的稳定性

四,以太网UDP通信仿真

仿真设计

对以太网UDP通信设计进行仿真,仿真代码如下:

  1. `timescale 1ns / 1ps
  2. module tb_top();
  3. parameter LOCAL_MAC_ADDR = {8'd0,8'd1,8'd2,8'd3,8'd4,8'd5};
  4. parameter TARGET_MAC_ADDR = {8'd0,8'd1,8'd2,8'd3,8'd4,8'd5};
  5. parameter LOCAL_IP_ADDR = {8'd0,8'd1,8'd2,8'd3};
  6. parameter TARGET_IP_ADDR = {8'd0,8'd1,8'd2,8'd3};
  7. parameter LOCAL_PORT = 16'h8060;
  8. parameter TARGET_PORT = 16'h8060;
  9. reg phy_clk ;
  10. reg clk ;
  11. reg reset ;
  12. wire gmii_rx_data_vld ;
  13. wire [7:0] gmii_rx_data ;
  14. wire gmii_tx_data_vld ;
  15. wire [7:0] gmii_tx_data ;
  16. wire app_rx_data_vld ;
  17. wire app_rx_data_last ;
  18. wire [7 :0] app_rx_data ;
  19. wire [15:0] app_rx_length ;
  20. reg app_tx_data_vld ;
  21. reg app_tx_data_last ;
  22. reg [7 :0] app_tx_data ;
  23. reg [15:0] app_tx_length ;
  24. wire app_tx_ready ;
  25. initial begin
  26. phy_clk = 0;
  27. forever # (4)
  28. phy_clk = ~ phy_clk;
  29. end
  30. initial begin
  31. clk = 0;
  32. forever # (10) //20ns
  33. clk = ~ clk;
  34. end
  35. initial begin
  36. reset = 1;
  37. #2000
  38. reset = 0;
  39. end
  40. /*----------------------------------------------------*\
  41. 发起APP请求
  42. \*----------------------------------------------------*/
  43. initial begin
  44. #300000
  45. upd_rw_test(18);
  46. upd_rw_test(1024);
  47. #3000;
  48. $stop;
  49. end
  50. /*----------------------------------------------------*\
  51. 封装task任务
  52. \*----------------------------------------------------*/
  53. task upd_rw_test
  54. (
  55. input [15:0] length
  56. );begin
  57. #3000;
  58. wait(app_tx_ready);
  59. app_tx_data_vld <= 0;
  60. app_tx_data_last <= 0;
  61. app_tx_length <= length;
  62. #400;
  63. repeat(length)@(posedge clk)begin
  64. app_tx_data_vld <= 1;
  65. end
  66. app_tx_data_vld <= 1;
  67. app_tx_data_last <= 1;
  68. #20;
  69. app_tx_data_vld <= 0;
  70. app_tx_data_last <= 0;
  71. end
  72. endtask
  73. always @(posedge clk ) begin
  74. if (reset) begin
  75. app_tx_data <= 0;
  76. end
  77. else if (app_tx_data_vld) begin
  78. app_tx_data <= app_tx_data + 1;
  79. end
  80. end
  81. assign gmii_rx_data_vld = gmii_tx_data_vld ;
  82. assign gmii_rx_data = gmii_tx_data ;
  83. udp_protocol_stack #(
  84. .LOCAL_MAC_ADDR(LOCAL_MAC_ADDR),
  85. .TARGET_MAC_ADDR(TARGET_MAC_ADDR),
  86. .LOCAL_IP_ADDR(LOCAL_IP_ADDR),
  87. .TARGET_IP_ADDR(TARGET_IP_ADDR),
  88. .LOCAL_PORT(LOCAL_PORT),
  89. .TARGET_PORT(TARGET_PORT)
  90. ) udp_protocol_stack (
  91. .phy_tx_clk (phy_clk),
  92. .phy_rx_clk (phy_clk),
  93. .reset (reset),
  94. .gmii_rx_data_vld (gmii_rx_data_vld),
  95. .gmii_rx_data (gmii_rx_data),
  96. .gmii_tx_data_vld (gmii_tx_data_vld),
  97. .gmii_tx_data (gmii_tx_data),
  98. .app_rx_clk (clk),
  99. .app_rx_data_vld (app_rx_data_vld),
  100. .app_rx_data_last (app_rx_data_last),
  101. .app_rx_data (app_rx_data),
  102. .app_rx_length (app_rx_length),
  103. .app_tx_clk (clk),
  104. .app_tx_data_vld (app_tx_data_vld),
  105. .app_tx_data_last (app_tx_data_last),
  106. .app_tx_data (app_tx_data),
  107. .app_tx_length (app_tx_length),
  108. .app_tx_ready (app_tx_ready)
  109. );
  110. endmodule

仿真波形

udp_send:

ip_send:

mac_send:

mac_receive:

mac_to_ip_arp:

ip_receive:

udp_receive:

top:

五,以太网UDP通信上板验证

修改源mac地址和ip地址,以及目标mac地址和ip地址。

  1. parameter LOCAL_MAC_ADDR = {8'h48,8'h2c,8'ha0,8'hdf,8'h00,8'hff};
  2. parameter TARGET_MAC_ADDR = {8'h88,8'ha4,8'hc2,8'hc8,8'h19,8'h11};
  3. parameter LOCAL_IP_ADDR = {8'd169,8'd254,8'd189,8'd137};
  4. parameter TARGET_IP_ADDR = {8'd169,8'd254,8'd189,8'd136};
  5. parameter LOCAL_PORT = 16'd1234;
  6. parameter TARGET_PORT = 16'd1234;

逻辑综合,布局布线,生成Bitstream:     

打开网络调试助手:

打开后点击发送:

可以看到可以正常接收。

六,总结

        我们完成了以太网udp通信的发送与接受。同时,也已经了解了MAC协议首部,IP协议首部,UDP协议首部的具体内容,并完成了各层的接受与发送。

        但是本次设计的以太网udp通信,只做了udp协议回环,不带arpicmp的功能,是简化版本的 udp工程,开发板和PC通信,需要手动在电脑端添加板卡的ip地址mac地址

        如下图,完整的以太网udp通信是包括arpicmp功能:

        但是,在我们的代码设计中,我们按每一层去编写设计代码,因此,想要完成完整的udp设计,只需要mac层后提添加ICMP功能,在ip层后添加ARP功能。添加这2个功能后要涉及一个很大的问题:仲裁,设计好仲裁后,就可以完成完整版本的udp工程。

      至此,简化版的以太网udp通信的发送与接受设计完成。

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

闽ICP备14008679号