问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 38 人浏览分享

开启左侧

UDP 巨型帧设计

[复制链接]
38 0
安路-FPGA课程
安路课程: 通信方案 » UDP通信原理以及三速UDP(支持巨帧)协议栈实现详解
安路系列: EG4
本帖最后由 UT发布 于 2025-4-3 15:34 编辑

软件版本:TD_5.6.4_Release_97693
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
登录米联客FPGA社区-www.uisrc.com视频课程、在线答疑!
1 巨型帧介绍

以太网数据帧的长度为6字节目的MAC地址+6字节源MAC地址+2字节类型+有效载荷+4字节FCSIEEE802.3协议规定,以太网帧长最小为64字节,最大为1518字节。MTUMaximum Transmission Unit,最大传输单元)指以太网的有效载荷部分的长度的最大值,为1500字节。

巨型帧(Jumbo Frame)是指MTU超过1500字节的以太网帧,通过分片进行数据传输。只有当传输第一个分片时,需要添加UDP头部,其他分片不添加,这样减少了非数据片段的开销,提高了带宽利用率。但巨型帧也会带来更大的延时,当巨型帧占用网络时,其它协议需要排队等待访问MAC的时间更长,当巨型帧出现错误时,数据重传也需要更长的时间。

在实际使用中,需要相互通讯的两个端口同时支持巨型帧,否则巨型帧会被滤除。

2 巨型帧程序设计
2.1 巨型帧帧格式

巨型帧由IP包头部的第7和第8这两个字节控制,其中高3bit为标志字段,低13bit为分片偏移字段。标志字段的功能如下:

bit1:保留位,不使用。

bit2Don`t Fragment,不分片标志,置1时表示不分片,置0时表示分片。

bit3More Fragment,更多分片标志,置1时表示下一个数据包是巨型帧的一个分片,一般在巨型帧除了最后一个分片的数据包都置1

分片偏移表示该分片在巨型帧中的位置,由于该字段只有13bit,而IPUDP总长度字段有16bit,所以该字段每加1表示8个字节的数据,比如当一个分片的UDP字段长度为1480时,第1个分片的分片偏移为0,第2个分片的分片偏移为1851480/8)。

假设一次传输5000字节的数据,巨型帧发送的示意图如下图所示。

image.jpg

巨型帧的处理需要在UDP层和IP层进行。

2.2 发送端设计

当开启巨型帧时,如果数据长度小于(IP包有效载荷长度-UDP首部长度),则作为普通帧发送,否则开启巨帧分片。

UDP层例化两个FIFO1个用于缓存用户端数据,1个用于缓存长度队列,当用户数据写入数据FIFO完成后,再把长度信息写入长度FIFO,用长度FIFO的空信号来判断是否有数据等待发送。

程序中通过状态机控制数据的发送,由于UDP层需要向IP层握手才能发送数据,状态机的控制会有些复杂。状态机的转换图如下图所示。

image.jpg

WAIT_PKG:初始状态,等待需要发送的数据包,当有数据包需要发送时,向IP层发送请求信号,状态机跳转至WAIT_ACK

WAIT_ACK:等待IP层握手响应,当发送第一包数据时,状态机跳转至PREPARE状态;当发送的不是第一包数据时,判断剩余的数据数量,如果剩余数据量小于最大有效载荷长度,则跳转至LAST_SPLIT状态,否则跳转至MID_SPLIT状态。

PREPARE:通过数据长度判断是否需要分片,需要分片则进入FIRST_SPLIT状态,否则进入SINGLE_PKG状态。

FIRST_SPLIT:发送第一个分片并且封装UDP头部,发送完成后进入WAIT_PAUSE状态。

SINGLE_SPLIT:发送一个完整的普通包,发送完成后进入WAIT_PAUSE状态。

MID_SPLIT:发送不包括第一个和末尾的分片,发送完成后进入WAIT_PAUSE状态。

LAST_SPLIT:发送最后一个分片,发送完成后进入WAIT_PAUSE状态。

WAIT_PAUSE:判断数据是否发送完成,发送完成则进入WAIT_PKG状态,否则继续向IP层发送请求信号,进入WAIT_ACK状态。

UDP层还需将DF标志、MF标志和分片偏移发送到IP层,在封装IP头部和计算IP首部校验时需要用到这些数据。设置了两个顶层参数用来控制巨型帧,JUMBO_ENABLE为巨型帧使能,置1时打开巨型帧,置0时关闭;JUMBO_PACKET为巨帧一个分片的长度。

uiudp_tx模块的代码如下:

  1. `timescale 1ns/1ps
  2. module  uiudp_tx#(
  3.     parameter                       JUMBO_ENABLE    =   1'b1,
  4.     parameter                       JUMBO_PACKET    =   16'd4048
  5. )
  6. (
  7.     input   wire    [15:0]          I_udp_local_port,   //UDP本地端口
  8.     input   wire    [15:0]          I_udp_dest_port,    //UDP目的端口
  9.     input   wire                    I_reset,
  10.     input   wire                    I_W_udp_clk,        //UDP写数据时钟  
  11.     input   wire                    I_W_udp_req,        //UDP写请求
  12.     input   wire                    I_W_udp_valid,      //UDP写有效
  13.     input   wire    [7:0]           I_W_udp_data,       //UDP写数据
  14.     input   wire    [15:0]          I_W_udp_len,        //UDP写长度
  15.     output  reg                     O_W_udp_busy,       //UDP写忙
  16.     input   wire                    I_udp_ip_tbusy,     //ip层发送忙
  17.     output  reg                     O_udp_ip_treq,      //udp请求发送数据到IP层
  18.     output  reg                     O_udp_ip_tvalid,    //udp发送udp包到ip层有效   
  19.     output  reg     [7:0]           O_udp_ip_tdata,     //udp发送udp包到ip
  20.     output  reg     [15:0]          O_udp_ip_tpkg_len,  //udp发送udp包长度   
  21.     output  wire    [15:0]          O_udp_ip_flag       //3bit flag + 13bit offset
  22. );
  23. localparam  MAX_FRAME_LEN   =   JUMBO_PACKET - 8;
  24. localparam  OFFSET          =   JUMBO_PACKET>>3;
  25. localparam  CHECKSUM        =   16'h0000;//假如UDP包不使用校验和功能,校验和部分需全部置0,UDP发送不对校验和计算
  26. reg  [1:0] SWFIFO;
  27. reg     [2:0] SRFIFO;
  28. localparam  WAIT_PKG    =   2'd0;
  29. localparam  PRE         =   2'd1;
  30. localparam  WRITE_FIFO  =   2'd2;
  31. localparam  WAIT_FIFO   =   'd0;
  32. localparam  WAIT_PAUSE  =   'd1;
  33. localparam  PREPARE     =   'd2;
  34. localparam  FIRST_SPLIT =   'd3;
  35. localparam  MID_SPLIT   =   'd4;
  36. localparam  LAST_SPLIT  =   'd5;
  37. localparam  SINGLE_PKG  =   'd6;
  38. localparam  WAIT_ACK    =   'd7;
  39. reg         fifo_data_wren      ;
  40. reg  [8:0]  fifo_data_din       ;
  41. reg         fifo_data_rden      ;
  42. wire [8:0]  fifo_data_dout      ;
  43. wire        fifo_data_full      ;
  44. wire        fifo_data_empty     ;
  45. wire [16:0] fifo_data_count     ;
  46. reg         fifo_info_wren      ;
  47. reg  [15:0] fifo_info_din       ;
  48. reg         fifo_info_rden      ;
  49. wire [15:0] fifo_info_dout      ;
  50. wire        fifo_info_full      ;
  51. wire        fifo_info_empty     ;
  52. wire [4:0]  fifo_info_count     ;
  53. wire        udp_send_ready      ;
  54. reg         udp_in_valid        ;
  55. reg  [7:0]  udp_in_data         ;   
  56. reg  [15:0] udp_in_len          ;
  57. wire        udp_in_last         ;   
  58. reg  [15:0] st_cnt              ;
  59. reg  [15:0] udp_length          ;
  60. reg         split_flag          ;
  61. reg         more_fragments      ;
  62. reg  [12:0] udp_offset          ;
  63. reg         udp_out_last        ;
  64. assign  udp_send_ready  =   (fifo_data_count > 'd20000 || fifo_info_count > 'd12) ? 0 : 1;
  65. assign  udp_in_last     =   udp_in_valid && ~I_W_udp_valid;
  66. assign  O_udp_ip_flag   =   {1'b0, ~split_flag, more_fragments, udp_offset};
  67. always @(posedge I_W_udp_clk) begin
  68.     udp_in_valid    <=  I_W_udp_valid;
  69.     udp_in_data     <=  I_W_udp_data;
  70.     udp_in_len      <=  I_W_udp_len;
  71. end
  72. always @(posedge I_W_udp_clk) begin
  73.     if(I_reset) begin
  74.         fifo_data_wren  <=  1'b0;
  75.         fifo_data_din   <=  65'd0;
  76.         fifo_info_wren  <=  1'b0;
  77.         fifo_info_din   <=  65'd0;
  78.         O_W_udp_busy    <=  0;
  79.         SWFIFO          <=  WAIT_PKG;
  80.     end
  81.     else begin
  82.         case(SWFIFO)
  83.             WAIT_PKG:begin
  84.                 if(I_W_udp_req && !O_W_udp_busy && udp_send_ready) begin
  85.                     O_W_udp_busy    <=  1;
  86.                     SWFIFO          <=  PRE;
  87.                 end
  88.                 else begin
  89.                     fifo_data_wren  <=  1'b0;
  90.                     fifo_data_din   <=  65'd0;
  91.                     fifo_info_wren  <=  1'b0;
  92.                     fifo_info_din   <=  65'd0;
  93.                     O_W_udp_busy    <=  0;
  94.                     SWFIFO          <=  WAIT_PKG;
  95.                 end
  96.             end
  97.             PRE:begin
  98.                 if(udp_in_valid) begin
  99.                     fifo_info_wren  <=  1;
  100.                     fifo_info_din   <=  I_W_udp_len;
  101.                     fifo_data_wren  <=  1;
  102.                     fifo_data_din   <=  {udp_in_last, udp_in_data};
  103.                     SWFIFO          <=  WRITE_FIFO;
  104.                 end
  105.             end
  106.             WRITE_FIFO:begin
  107.                 fifo_info_wren  <=  0;
  108.                 fifo_info_din   <=  0;
  109.                 fifo_data_wren  <=  1;
  110.                 fifo_data_din   <=  {udp_in_last, udp_in_data};
  111.                 if(udp_in_valid && ~I_W_udp_valid) begin
  112.                     O_W_udp_busy    <=  0;
  113.                     SWFIFO          <=  WAIT_PKG;
  114.                 end
  115.             end
  116.             default:begin
  117.                 fifo_data_wren  <=  1'b0;
  118.                 fifo_data_din   <=  65'd0;
  119.                 fifo_info_wren  <=  1'b0;
  120.                 fifo_info_din   <=  65'd0;
  121.                 O_W_udp_busy    <=  0;
  122.                 SWFIFO          <=  WAIT_PKG;                  
  123.             end
  124.         endcase
  125.     end
  126. end
  127. udp_data_fifo udp_data_fifo
  128. (
  129.     .clk                (I_W_udp_clk),
  130.     .srst               (I_reset),
  131.     .din                (fifo_data_din),
  132.     .wr_en              (fifo_data_wren),
  133.     .rd_en              (fifo_data_rden),
  134.     .dout               (fifo_data_dout),
  135.     .full               (fifo_data_full),
  136.     .empty              (fifo_data_empty),
  137.     .data_count         (fifo_data_count)
  138. );
  139. udp_info_fifo udp_info_fifo
  140. (
  141.     .clk                (I_W_udp_clk),
  142.     .srst               (I_reset),
  143.     .din                (fifo_info_din),
  144.     .wr_en              (fifo_info_wren),
  145.     .rd_en              (fifo_info_rden),
  146.     .dout               (fifo_info_dout),
  147.     .full               (fifo_info_full),
  148.     .empty              (fifo_info_empty),
  149.     .data_count         (fifo_info_count)
  150. );
  151. always@(posedge I_W_udp_clk) begin
  152.     if(I_reset)
  153.         st_cnt  <=  0;
  154.     else if(SRFIFO == WAIT_PKG)
  155.         st_cnt  <=  0;
  156.     else if(SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG || SRFIFO == MID_SPLIT || SRFIFO == LAST_SPLIT)
  157.         st_cnt  <=  st_cnt + 1;
  158.     else
  159.         st_cnt  <=  0;
  160. end
  161. always@(posedge I_W_udp_clk) begin
  162.     if(I_reset)
  163.         SRFIFO  <=  WAIT_PKG;
  164.     else begin
  165.         case(SRFIFO)
  166.             WAIT_PKG:begin
  167.                 if(!fifo_info_empty && !I_udp_ip_tbusy)
  168.                     SRFIFO <=   WAIT_ACK;
  169.                 else
  170.                     SRFIFO  <=  WAIT_PKG;
  171.             end
  172.             WAIT_PAUSE:begin
  173.                 if(!split_flag)
  174.                     SRFIFO  <=  WAIT_PKG;
  175.                 else if(!I_udp_ip_tbusy && split_flag)
  176.                     SRFIFO  <=  WAIT_ACK;
  177.                 else
  178.                     SRFIFO  <=  WAIT_PAUSE;
  179.             end
  180.             WAIT_ACK:begin
  181.                 if(I_udp_ip_tbusy)
  182.                     if(!split_flag)
  183.                         SRFIFO  <=  PREPARE;
  184.                     else if((udp_offset + OFFSET) > (udp_length >> 3))
  185.                         SRFIFO  <=  LAST_SPLIT;
  186.                     else
  187.                         SRFIFO  <=  MID_SPLIT;
  188.                 else
  189.                     SRFIFO  <=  WAIT_ACK;
  190.             end
  191.             PREPARE:begin
  192.                 if(fifo_info_dout > MAX_FRAME_LEN && JUMBO_ENABLE)
  193.                     SRFIFO  <=  FIRST_SPLIT;
  194.                 else
  195.                     SRFIFO  <=  SINGLE_PKG;
  196.             end
  197.             FIRST_SPLIT, MID_SPLIT, LAST_SPLIT, SINGLE_PKG:begin
  198.                 if(udp_out_last)
  199.                     SRFIFO  <=  WAIT_PAUSE;
  200.                 else
  201.                     SRFIFO  <=  SRFIFO;
  202.             end
  203.             default:begin
  204.                 SRFIFO  <=  WAIT_PKG;
  205.             end
  206.         endcase
  207.     end
  208. end
  209. always@(posedge I_W_udp_clk) begin
  210.     if(I_reset)
  211.         O_udp_ip_treq   <=  0;
  212.     else if(I_udp_ip_tbusy)
  213.         O_udp_ip_treq   <=  0;
  214.     else if(SRFIFO == WAIT_PAUSE && !I_udp_ip_tbusy && split_flag)
  215.         O_udp_ip_treq   <=  1;
  216.     else if(SRFIFO == WAIT_PKG && !fifo_info_empty && !I_udp_ip_tbusy)
  217.         O_udp_ip_treq   <=  1;
  218.     else
  219.         O_udp_ip_treq   <=  O_udp_ip_treq;
  220. end
  221. always@(posedge I_W_udp_clk) begin
  222.     if(I_reset)
  223.         fifo_info_rden  <=  0;
  224.     else if(SRFIFO == WAIT_PKG && !fifo_info_empty && !I_udp_ip_tbusy)
  225.         fifo_info_rden  <=  1;
  226.     else
  227.         fifo_info_rden  <=  0;
  228. end
  229. always@(posedge I_W_udp_clk) begin
  230.     if(I_reset)
  231.         fifo_data_rden  <=  0;
  232.     else if(fifo_data_dout[8] && fifo_data_rden)
  233.         fifo_data_rden  <=  0;
  234.     else if(st_cnt == JUMBO_PACKET && JUMBO_ENABLE)
  235.         fifo_data_rden  <=  0;
  236.     else if((SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG) && st_cnt == 'd8)
  237.         fifo_data_rden  <=  1;
  238.     else if((SRFIFO == MID_SPLIT || SRFIFO == LAST_SPLIT) && st_cnt == 'd0)
  239.         fifo_data_rden  <=  1;
  240.     else
  241.         fifo_data_rden  <=  fifo_data_rden;
  242. end
  243. always@(posedge I_W_udp_clk) begin
  244.     if(I_reset)
  245.         udp_length  <=  0;
  246.     else if(SRFIFO == PREPARE)
  247.         udp_length  <=  fifo_info_dout + 16'd8;
  248.     else
  249.         udp_length  <=  udp_length;
  250. end
  251. always@(posedge I_W_udp_clk) begin
  252.     if(I_reset)
  253.         split_flag  <=  0;
  254.     else if(SRFIFO == LAST_SPLIT && udp_out_last)
  255.         split_flag  <=  0;
  256.     else if(SRFIFO == PREPARE && fifo_info_dout > MAX_FRAME_LEN && JUMBO_ENABLE)
  257.         split_flag  <=  1;
  258.     else
  259.         split_flag  <=  split_flag;
  260. end
  261. always@(posedge I_W_udp_clk) begin
  262.     if(I_reset)
  263.         more_fragments  <=  0;
  264.     else if(SRFIFO == FIRST_SPLIT || SRFIFO == MID_SPLIT)
  265.         more_fragments  <=  1;
  266.     else
  267.         more_fragments  <=  0;
  268. end
  269. always@(posedge I_W_udp_clk) begin
  270.     if(I_reset)
  271.         udp_out_last    <=  0;
  272.     else if(fifo_data_dout[8] && fifo_data_rden)
  273.         udp_out_last    <=  1;
  274.     else if(st_cnt == JUMBO_PACKET && JUMBO_ENABLE)
  275.         udp_out_last    <=  1;
  276.     else
  277.         udp_out_last    <=  0;
  278. end
  279. always@(posedge I_W_udp_clk) begin
  280.     if(I_reset)
  281.         O_udp_ip_tdata  <=  0;
  282.     else if(SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG)
  283.         case(st_cnt)
  284.             1       :O_udp_ip_tdata <=  I_udp_local_port[15:8];
  285.             2       :O_udp_ip_tdata <=  I_udp_local_port[7:0];
  286.             3       :O_udp_ip_tdata <=  I_udp_dest_port[15:8];
  287.             4       :O_udp_ip_tdata <=  I_udp_dest_port[7:0];
  288.             5       :O_udp_ip_tdata <=  udp_length[15:8];
  289.             6       :O_udp_ip_tdata <=  udp_length[7:0];
  290.             7       :O_udp_ip_tdata <=  CHECKSUM[15:8];
  291.             8       :O_udp_ip_tdata <=  CHECKSUM[7:0];
  292.             default :O_udp_ip_tdata <=  fifo_data_dout[7:0];
  293.         endcase
  294.     else
  295.         O_udp_ip_tdata  <=  fifo_data_dout[7:0];
  296. end
  297. always@(posedge I_W_udp_clk) begin
  298.     if(I_reset)
  299.         O_udp_ip_tvalid <=  0;
  300.     else if(udp_out_last)
  301.         O_udp_ip_tvalid <=  0;
  302.     else if(SRFIFO == FIRST_SPLIT || SRFIFO == SINGLE_PKG || SRFIFO == MID_SPLIT || SRFIFO == LAST_SPLIT)
  303.         O_udp_ip_tvalid <=  st_cnt > 0;
  304.     else
  305.         O_udp_ip_tvalid <=  O_udp_ip_tvalid;
  306. end
  307. always@(posedge I_W_udp_clk) begin
  308.     if(I_reset)
  309.         O_udp_ip_tpkg_len   <=  0;
  310.     else if(fifo_info_rden)
  311.         O_udp_ip_tpkg_len   <=  JUMBO_ENABLE ? fifo_info_dout > MAX_FRAME_LEN ? JUMBO_PACKET : fifo_info_dout + 8 : fifo_info_dout + 8;
  312.     else if(SRFIFO == WAIT_PAUSE && (udp_offset + OFFSET) > (udp_length >> 3))
  313.         O_udp_ip_tpkg_len   <=  udp_length - (udp_offset << 3);
  314.     else if(SRFIFO == WAIT_PAUSE )
  315.         O_udp_ip_tpkg_len   <=  JUMBO_PACKET;
  316.     else
  317.         O_udp_ip_tpkg_len   <=  O_udp_ip_tpkg_len;
  318. end
  319. always@(posedge I_W_udp_clk) begin
  320.     if(I_reset)
  321.         udp_offset  <=  0;
  322.     else if(SRFIFO == WAIT_PKG)
  323.         udp_offset  <=  0;
  324.     else if(SRFIFO != LAST_SPLIT && udp_out_last && O_udp_ip_tvalid)
  325.         udp_offset  <=  udp_offset + OFFSET;
  326.     else
  327.         udp_offset  <=  udp_offset;
  328. end
  329. endmodule
复制代码
2.3 接收端设计

首先在IP层把IP包头的MF标志解析出来,发送到UDP层用于判断数据包是否为分片,如果是分片,则继续将下一个数据包写入FIFO,等待全部数据包写入FIFO完成后,再将完整的有效数据段读出。

uiudp_rx代码如下:

  1. module  uiudp_rx
  2. (
  3.     input   wire                I_reset,
  4.     input   wire                I_R_udp_clk,        //udp接收时钟,和ip_layer接收的数据时钟相同
  5.     output  reg                 O_R_udp_valid,      //输出到用户层udp读数据有效
  6.     output  reg     [7:0]       O_R_udp_data,       //输出到用户层udp数据
  7.     output  reg     [15:0]      O_R_udp_len,        //输出到用户层读udp数据长度
  8.     output  reg     [15:0]      O_R_udp_src_port,   //输出到用户层接收到的UDP数据包的端口号
  9.     input   wire                I_udp_ip_rvalid,    //udp接收来自ip层的数据有效信号
  10.     input   wire    [7:0]       I_udp_ip_rdata,     //udp接收来自ip层数据
  11.     input   wire                I_udp_ip_rmf
  12. );
  13. reg                         fifo_data_rden;
  14. wire    [8:0]               fifo_data_dout;
  15. wire                        fifo_data_full;
  16. wire                        fifo_data_empty;
  17. wire    [16:0]              fifo_data_count;
  18. reg                         fifo_info_rden;
  19. wire    [15:0]              fifo_info_dout;
  20. wire                        fifo_info_full;
  21. wire                        fifo_info_empty;
  22. wire    [4:0]               fifo_info_count;
  23. reg                         rec_data_valid;
  24. reg     [7:0]               rec_data;
  25. reg                         rec_data_mf;//打拍信号
  26. reg     [15:0]              rx_length;
  27. reg                         info_lock;
  28. reg     [15:0]              rx_cnt;
  29. reg     [15:0]              fifo_cnt;
  30. reg     [15:0]              udp_pkg_len;
  31. reg     [15:0]              udp_length;
  32. always@(posedge I_R_udp_clk) begin
  33.     rec_data_valid  <=  I_udp_ip_rvalid;
  34.     rec_data        <=  I_udp_ip_rdata;
  35.     rec_data_mf     <=  I_udp_ip_rmf;
  36. end
  37. udp_data_fifo udp_data_fifo
  38. (
  39.     .clk                (I_R_udp_clk),
  40.     .srst               (I_reset),
  41.     .din                ({1'b0, I_udp_ip_rdata}),
  42.     .wr_en              (I_udp_ip_rvalid),
  43.     .rd_en              (fifo_data_rden),
  44.     .dout               (fifo_data_dout),
  45.     .full               (fifo_data_full),
  46.     .empty              (fifo_data_empty),
  47.     .data_count         (fifo_data_count)
  48. );
  49. udp_info_fifo udp_info_fifo
  50. (
  51.     .clk                (I_R_udp_clk),
  52.     .srst               (I_reset),
  53.     .din                (rx_length),
  54.     .wr_en              (rec_data_valid && ~I_udp_ip_rvalid && ~rec_data_mf),
  55.     .rd_en              (fifo_info_rden),
  56.     .dout               (fifo_info_dout),
  57.     .full               (fifo_info_full),
  58.     .empty              (fifo_info_empty),
  59.     .data_count         (fifo_info_count)
  60. );
  61. always@(posedge I_R_udp_clk or posedge I_reset) begin
  62.     if(I_reset)
  63.         fifo_cnt    <=  0;
  64.     else if(I_udp_ip_rvalid)
  65.         fifo_cnt    <=  fifo_cnt + 1;
  66.     else
  67.         fifo_cnt    <=  0;
  68. end
  69. always@(posedge I_R_udp_clk or posedge I_reset) begin
  70.     if(I_reset)
  71.         info_lock   <=  0;
  72.     else if(fifo_cnt == 6)
  73.         info_lock   <=  I_udp_ip_rmf ? 1 : 0;
  74.     else
  75.         info_lock   <=  info_lock;
  76. end
  77. always@(posedge I_R_udp_clk or posedge I_reset) begin
  78.     if(I_reset)
  79.         rx_length   <=  0;
  80.     else if((fifo_cnt == 4 || fifo_cnt == 5) && !info_lock)
  81.         rx_length   <=  {rx_length[7:0], I_udp_ip_rdata[7:0]};
  82.     else
  83.         rx_length   <=  rx_length;
  84. end
  85. always@(posedge I_R_udp_clk or posedge I_reset) begin
  86.     if(I_reset)
  87.         udp_length  <=  0;
  88.     else if(fifo_info_rden)
  89.         udp_length  <=  fifo_info_dout < 26 ? 26 : fifo_info_dout;
  90.     else
  91.         udp_length  <=  udp_length;
  92. end
  93. always@(posedge I_R_udp_clk or posedge I_reset) begin
  94.     if(I_reset)
  95.         udp_pkg_len <=  0;
  96.     else if(fifo_info_rden)
  97.         udp_pkg_len <=  fifo_info_dout;
  98.     else
  99.         udp_pkg_len <=  udp_pkg_len;
  100. end
  101. always@(posedge I_R_udp_clk or posedge I_reset) begin
  102.     if(I_reset)
  103.         fifo_info_rden  <=  0;
  104.     else if(fifo_info_rden || fifo_data_rden)
  105.         fifo_info_rden  <=  0;
  106.     else if(!fifo_info_empty)
  107.         fifo_info_rden  <=  1;
  108.     else
  109.         fifo_info_rden  <=  0;
  110. end
  111. always@(posedge I_R_udp_clk or posedge I_reset) begin
  112.     if(I_reset)
  113.         fifo_data_rden  <=  0;
  114.     else if(rx_cnt == udp_length - 1)
  115.         fifo_data_rden  <=  0;
  116.     else if(fifo_info_rden)
  117.         fifo_data_rden  <=  1;
  118.     else
  119.         fifo_data_rden  <=  fifo_data_rden;
  120. end
  121. always@(posedge I_R_udp_clk or posedge I_reset) begin
  122.     if(I_reset)
  123.         rx_cnt  <=  0;
  124.     else if(fifo_data_rden)
  125.         rx_cnt  <=  rx_cnt + 1;
  126.     else
  127.         rx_cnt  <=  0;
  128. end
  129. always@(posedge I_R_udp_clk or posedge I_reset) begin
  130.     if(I_reset)
  131.         O_R_udp_valid   <=  0;
  132.     else if(rx_cnt > 7 && rx_cnt < udp_pkg_len)
  133.         O_R_udp_valid   <=  1;
  134.     else
  135.         O_R_udp_valid   <=  0;
  136. end
  137. always@(posedge I_R_udp_clk or posedge I_reset) begin
  138.     if(I_reset)
  139.         O_R_udp_data    <=  0;
  140.     else if(rx_cnt > 7 && rx_cnt < udp_pkg_len)
  141.         O_R_udp_data    <=  fifo_data_dout[7:0];
  142.     else
  143.         O_R_udp_data    <=  0;
  144. end
  145. always@(posedge I_R_udp_clk or posedge I_reset) begin
  146.     if(I_reset)
  147.         O_R_udp_len <=  0;
  148.     else if(fifo_info_rden)
  149.         O_R_udp_len <=  fifo_info_dout - 8;
  150.     else
  151.         O_R_udp_len <=  O_R_udp_len;
  152. end
  153. always@(posedge I_R_udp_clk or posedge I_reset) begin
  154.     if(I_reset)
  155.         O_R_udp_src_port    <=  0;
  156.     else if(fifo_data_rden && (rx_cnt == 0 || rx_cnt == 1))
  157.         O_R_udp_src_port    <=  {O_R_udp_src_port[7:0], fifo_data_dout[7:0]};
  158.     else
  159.         O_R_udp_src_port    <=  O_R_udp_src_port;
  160. end
  161. endmodule
复制代码
3 巨型帧验证3.1 仿真验证

首先对设计完成的uiudp_tx模块进行仿真验证,设置JUMBO_ENABLE1JUMBO_PACKET1480,用户端持续发送一段长度为5000字节的测试数据,仿真波形图如下图所示。

image.jpg

数据被分成了4个分片依次发送出去,前3个分片的UDP长度为1480,最后1个分片的UDP长度为568,则数据发送的长度正确(1480*3+568-8=5000)。标志位分别为3b0013b0013b0013b000,标志位都正确。偏移量的计算为(片偏移字段*8),则偏移量分别为0148029604440,偏移量都正确。

将发送端发送的巨型帧通过MAC回环进接收端,uiudp_rx模块的仿真波形图如下图所示。

IP层解析出MF信号用于UDP层判断数据是独立的还是巨帧分片,当4个巨帧分片都写入FIFO后,将FIFO中的数据读出重组成为完整的5000字节的数据流。

3.2上板验证

首先在电脑“设备管理器”中展开“网络适配器”选项,找到自己的网卡,双击进入设置。

image.jpg


在高级选项卡中,找到巨型帧选项开启,不同厂家设置的传输单元大小可能有所不同,本次验证选择4088Bytes


image.jpg

首先使用网络调试助手发送一个巨型帧,通过wireshark软件抓取。

image.jpg

可以抓到每一帧的长度为4082,则JUMBO_FRAME的参数设置为40484082-20IP首部)-14MAC首部))。将程序下载进开发板中,首先通过ping包测试网络是否通畅。

image.jpg

接着通过网络调试助手进行回环测试。

image.jpg

可以看到收发数据量一致,并且环回的数据正确。通过wireshark抓取的数据包如下图所示,红框为电脑向开发板发送的巨帧分片,在最后一个分片时重组成为巨型帧。

image.jpg

在网络调试助手发送64000字节长度的数据,验证巨型帧最大帧长。网络调试助手接收到的数据如下图所示。

image.jpg

wireshark抓取的数据如下图所示。

image.jpg
































您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

0

粉丝

272

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版