OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4352|回复: 7

[XILINX] FPGA+千兆网实测速率只有4Mbit/s?

[复制链接]

11

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2017-8-17
在线时间
50 小时
发表于 2022-1-14 10:25:48 | 显示全部楼层 |阅读模式
使用达芬奇FPGA开发板上的千兆网口测试UDP通信速率。将原子核提供的UDP回环例程改了一下。改成10S内持续由FPGA千兆网口发送数据至PC端。经实测发现,每个包数据大小为1401字节,10秒只接收到了4419个包,开始的时候包没有丢失,后面数据包有间隔丢失,具体开始丢失的位置没有花时间去找。在代码里每发一个包会添加1us的时间延时,不然的话实测速率就只有几十Kbit/s了,而且从第二个包开始就丢了几千个包了,所以包之间加了延时。不太明白这里速率的瓶颈被什么给限制住了,已经可以确定PC是千兆网口。这里将做了更改的代码文件上传一下。其他不变的同原子哥提供的例程(eth_udp_loop)一样。

module eth_udp_loop(
    input              sys_clk   , //系统时钟
    input              sys_rst_n , //系统复位信号,低电平有效
        input [1:0]        key       ,
    //以太网RGMII接口   
    input              eth_rxc   , //RGMII接收数据时钟
    input              eth_rx_ctl, //RGMII输入数据有效信号
    input       [3:0]  eth_rxd   , //RGMII输入数据
    output             eth_txc   , //RGMII发送数据时钟   
    output             eth_tx_ctl, //RGMII输出数据有效信号
    output      [3:0]  eth_txd   , //RGMII输出数据         
    output             eth_rst_n   //以太网芯片复位信号,低电平有效   
    );


//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter  BOARD_MAC = 48'h00_11_22_33_44_55;     
//开发板IP地址 192.168.1.10
parameter  BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};  
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;   
//目的IP地址 192.168.1.102     
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102};  
//输入数据IO延时,此处为0,即不延时(如果为n,表示延时n*78ps)
parameter IDELAY_VALUE = 0;


//wire define
wire          clk_200m   ; //用于IO延时的时钟
              
wire          gmii_rx_clk; //GMII接收时钟
wire          gmii_rx_dv ; //GMII接收数据有效信号
wire  [7:0]   gmii_rxd   ; //GMII接收数据
wire          gmii_tx_clk; //GMII发送时钟
wire          gmii_tx_en ; //GMII发送数据使能信号
wire  [7:0]   gmii_txd   ; //GMII发送数据     


wire          arp_gmii_tx_en; //ARP GMII输出数据有效信号
wire  [7:0]   arp_gmii_txd  ; //ARP GMII输出数据
wire          arp_rx_done   ; //ARP接收完成信号
wire          arp_rx_type   ; //ARP接收类型 0:请求  1:应答
wire  [47:0]  src_mac       ; //接收到目的MAC地址
wire  [31:0]  src_ip        ; //接收到目的IP地址   
wire          arp_tx_en     ; //ARP发送使能信号
wire          arp_tx_type   ; //ARP发送类型 0:请求  1:应答
wire  [47:0]  des_mac       ; //发送的目标MAC地址
wire  [31:0]  des_ip        ; //发送的目标IP地址   
wire          arp_tx_done   ; //ARP发送完成信号


wire          udp_gmii_tx_en; //UDP GMII输出数据有效信号
wire  [7:0]   udp_gmii_txd  ; //UDP GMII输出数据
wire          rec_pkt_done  ; //UDP单包数据接收完成信号
reg          rec_en        ; //UDP接收的数据使能信号
reg  [31:0]  rec_data      ; //UDP接收的数据
wire  [15:0]  rec_byte_num  ; //UDP接收的有效字节数 单位:byte
wire  [15:0]  tx_byte_num   ; //UDP发送的有效字节数 单位:byte
wire          udp_tx_done   ; //UDP发送完成信号
wire          tx_req        ; //UDP读数据请求信号
wire  [31:0]  tx_data       ; //UDP待发送数据


reg tx_start_en;
reg key_flag;
reg [10:0] delay;
reg [31:0] time_10s;
reg [31:0] delay1;
//*****************************************************
//**                    main code
//*****************************************************


//assign tx_start_en = rec_pkt_done;
assign tx_byte_num = 12'd1401;
assign des_mac = src_mac;
assign des_ip = src_ip;
assign eth_rst_n = sys_rst_n;


//按键0按下启动网口数据发送,按键1按下停止网口数据发送
always @(posedge eth_txc or negedge sys_rst_n) begin
    if(!sys_rst_n) begin
        tx_start_en <= 1'b0;
                time_10s<=32'd0;
                delay1<=32'd0;
    end   
    else if((key_flag==1)&&(time_10s<32'd1250000000))
        begin
                time_10s<=time_10s+1'b1;
                tx_start_en <= 1'b1;
                if(udp_tx_done)
                begin
                        tx_start_en <= 1'b0;
                end
                if(~tx_start_en)
                begin
                        delay1<=delay1+1'b1;
                        if(delay1>125)//1us
                        begin
                                delay1<=32'd0;
                                tx_start_en<=1'b1;
                        end
                end
    end
        else if((key_flag==0)||(time_10s>=32'd1250000000))
        begin
        tx_start_en <= 1'b0;
    end
end




always @(posedge eth_txc or negedge sys_rst_n)
begin
        if(!sys_rst_n)
        begin
                key_flag<=1'b0;
                delay<=10'd0;
        end
        else if(key[0]==0)
        begin
                delay<=delay+1'b1;
                if((delay>=500)&&(key[0]==0))
                begin
                        key_flag<=1'b1;
                        delay<=10'd0;
                end
        end
        else if(key[1]==0)
        begin
                delay<=delay+1'b1;
                if((delay>=500)&&(key[1]==0))
                begin
                        key_flag<=1'b0;
                        delay<=10'd0;
                end
        end
end


//模拟数据
always @(posedge eth_txc or negedge sys_rst_n)
begin
    if(!sys_rst_n) begin
        rec_data <= 32'b0;
                rec_en<=1'b0;
    end   
    else if(tx_start_en==1)
        begin
        rec_data <= rec_data+1'b1;
                if(rec_data%4==0)
                begin
                        rec_en<=1'b1;
                end
                else
                begin
                        rec_en<=1'b0;
                end
    end
end


//MMCM/PLL
clk_wiz u_clk_wiz
(
    .clk_in1   (sys_clk   ),
    .clk_out1  (clk_200m  ),   
    .reset     (~sys_rst_n),
    .locked    (locked)
);


//GMII接口转RGMII接口
gmii_to_rgmii
    #(
     .IDELAY_VALUE (IDELAY_VALUE)
     )
    u_gmii_to_rgmii(
    .idelay_clk    (clk_200m    ),


    .gmii_rx_clk   (gmii_rx_clk ),
    .gmii_rx_dv    (gmii_rx_dv  ),
    .gmii_rxd      (gmii_rxd    ),
    .gmii_tx_clk   (gmii_tx_clk ),
    .gmii_tx_en    (gmii_tx_en  ),
    .gmii_txd      (gmii_txd    ),
   
    .rgmii_rxc     (eth_rxc     ),
    .rgmii_rx_ctl  (eth_rx_ctl  ),
    .rgmii_rxd     (eth_rxd     ),
    .rgmii_txc     (eth_txc     ),
    .rgmii_tx_ctl  (eth_tx_ctl  ),
    .rgmii_txd     (eth_txd     )
    );


//ARP通信
arp                                             
   #(
    .BOARD_MAC     (BOARD_MAC),      //参数例化
    .BOARD_IP      (BOARD_IP ),
    .DES_MAC       (DES_MAC  ),
    .DES_IP        (DES_IP   )
    )
   u_arp(
    .rst_n         (sys_rst_n  ),
                    
    .gmii_rx_clk   (gmii_rx_clk),
    .gmii_rx_dv    (gmii_rx_dv ),
    .gmii_rxd      (gmii_rxd   ),
    .gmii_tx_clk   (gmii_tx_clk),
    .gmii_tx_en    (arp_gmii_tx_en ),
    .gmii_txd      (arp_gmii_txd),
                    
    .arp_rx_done   (arp_rx_done),
    .arp_rx_type   (arp_rx_type),
    .src_mac       (src_mac    ),
    .src_ip        (src_ip     ),
    .arp_tx_en     (arp_tx_en  ),
    .arp_tx_type   (arp_tx_type),
    .des_mac       (des_mac    ),
    .des_ip        (des_ip     ),
    .tx_done       (arp_tx_done)
    );


//UDP通信
udp                                             
   #(
    .BOARD_MAC     (BOARD_MAC),      //参数例化
    .BOARD_IP      (BOARD_IP ),
    .DES_MAC       (DES_MAC  ),
    .DES_IP        (DES_IP   )
    )
   u_udp(
    .rst_n         (sys_rst_n   ),  
   
    .gmii_rx_clk   (gmii_rx_clk ),           
    .gmii_rx_dv    (gmii_rx_dv  ),         
    .gmii_rxd      (gmii_rxd    ),                  
    .gmii_tx_clk   (gmii_tx_clk ),
    .gmii_tx_en    (udp_gmii_tx_en),         
    .gmii_txd      (udp_gmii_txd),  


    .rec_pkt_done  (rec_pkt_done),   
    .rec_en        (      ),     
    .rec_data      (    ),         
    .rec_byte_num  (rec_byte_num),      
    .tx_start_en   (tx_start_en ),        
    .tx_data       (tx_data     ),         
    .tx_byte_num   (tx_byte_num ),  
    .des_mac       (des_mac     ),
    .des_ip        (des_ip      ),   
    .tx_done       (udp_tx_done ),        
    .tx_req        (tx_req      )           
    );


//同步FIFO
sync_fifo_2048x32b u_sync_fifo_2048x32b (
    .clk      (gmii_rx_clk),  // input wire clk
    .rst      (~sys_rst_n),  // input wire rst
    .din      (rec_data  ),  // input wire [31 : 0] din
    .wr_en    (rec_en    ),  // input wire wr_en
    .rd_en    (tx_req    ),  // input wire rd_en
    .dout     (tx_data   ),  // output wire [31 : 0] dout
    .full     (),            // output wire full
    .empty    ()             // output wire empty
    );   


//以太网控制模块
eth_ctrl u_eth_ctrl(
    .clk            (gmii_rx_clk),
    .rst_n          (sys_rst_n),


    .arp_rx_done    (arp_rx_done   ),
    .arp_rx_type    (arp_rx_type   ),
    .arp_tx_en      (arp_tx_en     ),
    .arp_tx_type    (arp_tx_type   ),
    .arp_tx_done    (arp_tx_done   ),
    .arp_gmii_tx_en (arp_gmii_tx_en),
    .arp_gmii_txd   (arp_gmii_txd  ),
                     
    .udp_gmii_tx_en (udp_gmii_tx_en),
    .udp_gmii_txd   (udp_gmii_txd  ),
                     
    .gmii_tx_en     (gmii_tx_en    ),
    .gmii_txd       (gmii_txd      )
    );


endmodule



第二个文件代码


module udp_tx(   
    input                clk        , //时钟信号
    input                rst_n      , //复位信号,低电平有效

    input                tx_start_en, //以太网开始发送信号
//    input        [31:0]  tx_data    , //以太网待发送数据  
    input        [15:0]  tx_byte_num, //以太网发送的有效字节数
    input        [47:0]  des_mac    , //发送的目标MAC地址
    input        [31:0]  des_ip     , //发送的目标IP地址   
    input        [31:0]  crc_data   , //CRC校验数据
    input         [7:0]  crc_next   , //CRC下次校验完成数据
    output  reg          tx_done    , //以太网发送完成信号
    output  reg          tx_req     , //读数据请求信号
    output  reg          gmii_tx_en , //GMII输出数据有效信号
    output  reg  [7:0]   gmii_txd   , //GMII输出数据
    output  reg          crc_en     , //CRC开始校验使能
    output  reg          crc_clr      //CRC数据复位信号
    );


//parameter define
//开发板MAC地址 00-11-22-33-44-55
parameter BOARD_MAC = 48'h00_11_22_33_44_55;
//开发板IP地址 192.168.1.10   
parameter BOARD_IP  = {8'd192,8'd168,8'd1,8'd10};
//目的MAC地址 ff_ff_ff_ff_ff_ff
parameter  DES_MAC   = 48'hff_ff_ff_ff_ff_ff;
//目的IP地址 192.168.1.102
parameter  DES_IP    = {8'd192,8'd168,8'd1,8'd102};

localparam  st_idle      = 7'b000_0001; //初始状态,等待开始发送信号
localparam  st_check_sum = 7'b000_0010; //IP首部校验和
localparam  st_preamble  = 7'b000_0100; //发送前导码+帧起始界定符
localparam  st_eth_head  = 7'b000_1000; //发送以太网帧头
localparam  st_ip_head   = 7'b001_0000; //发送IP首部+UDP首部
localparam  st_tx_data   = 7'b010_0000; //发送数据
localparam  st_crc       = 7'b100_0000; //发送CRC校验值

localparam  ETH_TYPE     = 16'h0800   ; //以太网协议类型 IP协议
//以太网数据最小46个字节,IP首部20个字节+UDP首部8个字节
//所以数据至少46-20-8=18个字节
localparam  MIN_DATA_NUM = 16'd18     ;  
localparam  UDP_TYPE    = 8'd17       ; //UDP协议类型  

reg [31:0] tx_data;
//reg define
reg  [6:0]   cur_state      ;
reg  [6:0]   next_state     ;

reg  [7:0]   preamble[7:0]  ; //前导码
reg  [7:0]   eth_head[13:0] ; //以太网首部
reg  [31:0]  ip_head[6:0]   ; //IP首部 + UDP首部

reg          start_en_d0    ;
reg          start_en_d1    ;
reg  [15:0]  tx_data_num    ; //发送的有效数据字节个数
reg  [15:0]  total_num      ; //总字节数
reg          trig_tx_en     ;
reg  [15:0]  udp_num        ; //UDP字节数
reg          skip_en        ; //控制状态跳转使能信号
reg  [4:0]   cnt            ;
reg  [31:0]  check_buffer   ; //首部校验和
reg  [1:0]   tx_byte_sel    ; //32位数据转8位数据计数器
reg  [15:0]  data_cnt       ; //发送数据个数计数器
reg          tx_done_t      ;
reg  [4:0]   real_add_cnt   ; //以太网数据实际多发的字节数


//wire define                       
wire         pos_start_en    ;//开始发送数据上升沿
wire [15:0]  real_tx_data_num;//实际发送的字节数(以太网最少字节要求)
//*****************************************************
//**                    main code
//*****************************************************

assign  pos_start_en = (~start_en_d1) & start_en_d0;
assign  real_tx_data_num = (tx_data_num >= MIN_DATA_NUM)
                           ? tx_data_num : MIN_DATA_NUM;

//采tx_start_en的上升沿
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        start_en_d0 <= 1'b0;
        start_en_d1 <= 1'b0;
    end   
    else begin
        start_en_d0 <= tx_start_en;
        start_en_d1 <= start_en_d0;
    end
end

//寄存数据有效字节
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        tx_data_num <= 16'd0;
        total_num <= 16'd0;
        udp_num <= 16'd0;
    end
    else begin
        if(pos_start_en && cur_state==st_idle) begin
            //数据长度
            tx_data_num <= tx_byte_num;     
            //UDP长度:UDP首部长度 + 有效数据            
            udp_num <= tx_byte_num + 16'd8;               
            //IP长度:IP首部长度 + UDP首部 + 有效数据            
            total_num <= tx_byte_num + 16'd20 + 16'd8;  
        end
    end
end

//触发发送信号
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        trig_tx_en <= 1'b0;
    else
        trig_tx_en <= pos_start_en;

end

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cur_state <= st_idle;  
    else
        cur_state <= next_state;
end

always @(*) begin
    next_state = st_idle;
    case(cur_state)
        st_idle     : begin                               //等待发送数据
            if(skip_en)               
                next_state = st_check_sum;
            else
                next_state = st_idle;
        end  
        st_check_sum: begin                               //IP首部校验
            if(skip_en)
                next_state = st_preamble;
            else
                next_state = st_check_sum;   
        end                             
        st_preamble : begin                               //发送前导码+帧起始界定符
            if(skip_en)
                next_state = st_eth_head;
            else
                next_state = st_preamble;      
        end
        st_eth_head : begin                               //发送以太网首部
            if(skip_en)
                next_state = st_ip_head;
            else
                next_state = st_eth_head;      
        end              
        st_ip_head : begin                                //发送IP首部+UDP首部               
            if(skip_en)
                next_state = st_tx_data;
            else
                next_state = st_ip_head;      
        end
        st_tx_data : begin                                //发送数据                  
            if(skip_en)
                next_state = st_crc;
            else
                next_state = st_tx_data;      
        end
        st_crc: begin                                     //发送CRC校验值
            if(skip_en)
                        begin
                                next_state = st_idle;
                        end
            else
                next_state = st_crc;
        end
        default : next_state = st_idle;
    endcase
end                     

//发送数据
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        skip_en <= 1'b0;
        cnt <= 5'd0;
        check_buffer <= 32'd0;
        ip_head[1][31:16] <= 16'd0;
        tx_byte_sel <= 2'b0;
        crc_en <= 1'b0;
        gmii_tx_en <= 1'b0;
        gmii_txd <= 8'd0;
        tx_req <= 1'b0;
        tx_done_t <= 1'b0;
        data_cnt <= 16'd0;
        real_add_cnt <= 5'd0;
                tx_data<=32'd0;
        //初始化数组   
        //前导码 7个8'h55 + 1个8'hd5
        preamble[0] <= 8'h55;                 
        preamble[1] <= 8'h55;
        preamble[2] <= 8'h55;
        preamble[3] <= 8'h55;
        preamble[4] <= 8'h55;
        preamble[5] <= 8'h55;
        preamble[6] <= 8'h55;
        preamble[7] <= 8'hd5;
        //目的MAC地址
        eth_head[0] <= DES_MAC[47:40];
        eth_head[1] <= DES_MAC[39:32];
        eth_head[2] <= DES_MAC[31:24];
        eth_head[3] <= DES_MAC[23:16];
        eth_head[4] <= DES_MAC[15:8];
        eth_head[5] <= DES_MAC[7:0];
        //源MAC地址
        eth_head[6] <= BOARD_MAC[47:40];
        eth_head[7] <= BOARD_MAC[39:32];
        eth_head[8] <= BOARD_MAC[31:24];
        eth_head[9] <= BOARD_MAC[23:16];
        eth_head[10] <= BOARD_MAC[15:8];
        eth_head[11] <= BOARD_MAC[7:0];
        //以太网类型
        eth_head[12] <= ETH_TYPE[15:8];
        eth_head[13] <= ETH_TYPE[7:0];        
    end
    else begin
        skip_en <= 1'b0;
        tx_req <= 1'b0;
        crc_en <= 1'b0;
        gmii_tx_en <= 1'b0;
                tx_done_t <= 1'b0;
        case(next_state)
            st_idle     : begin
                if(trig_tx_en) begin
                                        tx_data<=tx_data+1'b1;
                    skip_en <= 1'b1;
                    //版本号:4 首部长度:5(单位:32bit,20byte/4=5)
                    ip_head[0] <= {8'h45,8'h00,total_num};   
                    //16位标识,每次发送累加1      
                    ip_head[1][31:16] <= ip_head[1][31:16] + 1'b1;
                    //bit[15:13]: 010表示不分片
                    ip_head[1][15:0] <= 16'h4000;   
                    //协议:17(udp)                  
                    ip_head[2] <= {8'h40,UDP_TYPE,16'h0};   
                    //源IP地址               
                    ip_head[3] <= BOARD_IP;
                    //目的IP地址   
                    if(des_ip != 32'd0)
                        ip_head[4] <= des_ip;
                    else
                        ip_head[4] <= DES_IP;      
                    //16位源端口号:1234  16位目的端口号:8811                     
                    ip_head[5] <= {16'd8811,16'd8811};  
                    //16位udp长度,16位udp校验和              
                    ip_head[6] <= {udp_num,16'h0000};  
                    //更新MAC地址
                    if(des_mac != 48'b0) begin
                        //目的MAC地址
                        eth_head[0] <= des_mac[47:40];
                        eth_head[1] <= des_mac[39:32];
                        eth_head[2] <= des_mac[31:24];
                        eth_head[3] <= des_mac[23:16];
                        eth_head[4] <= des_mac[15:8];
                        eth_head[5] <= des_mac[7:0];
                    end
                end   
            end                                                      
            st_check_sum: begin                           //IP首部校验
                cnt <= cnt + 5'd1;
                if(cnt == 5'd0) begin                  
                    check_buffer <= ip_head[0][31:16] + ip_head[0][15:0]
                                    + ip_head[1][31:16] + ip_head[1][15:0]
                                    + ip_head[2][31:16] + ip_head[2][15:0]
                                    + ip_head[3][31:16] + ip_head[3][15:0]
                                    + ip_head[4][31:16] + ip_head[4][15:0];
                end
                else if(cnt == 5'd1)                      //可能出现进位,累加一次
                    check_buffer <= check_buffer[31:16] + check_buffer[15:0];
                else if(cnt == 5'd2) begin                //可能再次出现进位,累加一次
                    check_buffer <= check_buffer[31:16] + check_buffer[15:0];
                end                             
                else if(cnt == 5'd3) begin                //按位取反
                    skip_en <= 1'b1;
                    cnt <= 5'd0;            
                    ip_head[2][15:0] <= ~check_buffer[15:0];
                end   
            end              
            st_preamble : begin                           //发送前导码+帧起始界定符
                gmii_tx_en <= 1'b1;
                gmii_txd <= preamble[cnt];
                if(cnt == 5'd7) begin                        
                    skip_en <= 1'b1;
                    cnt <= 5'd0;   
                end
                else   
                    cnt <= cnt + 5'd1;                     
            end
            st_eth_head : begin                           //发送以太网首部
                gmii_tx_en <= 1'b1;
                crc_en <= 1'b1;
                gmii_txd <= eth_head[cnt];
                if (cnt == 5'd13) begin
                    skip_en <= 1'b1;
                    cnt <= 5'd0;
                end   
                else   
                    cnt <= cnt + 5'd1;   
            end                    
            st_ip_head  : begin                           //发送IP首部 + UDP首部
                crc_en <= 1'b1;
                gmii_tx_en <= 1'b1;
                tx_byte_sel <= tx_byte_sel + 2'd1;
                if(tx_byte_sel == 2'd0)
                    gmii_txd <= ip_head[cnt][31:24];
                else if(tx_byte_sel == 2'd1)
                    gmii_txd <= ip_head[cnt][23:16];
                else if(tx_byte_sel == 2'd2) begin
                    gmii_txd <= ip_head[cnt][15:8];
                    if(cnt == 5'd6) begin
                        //提前读请求数据,等待数据有效时发送
                        tx_req <= 1'b1;                     
                    end
                end
                else if(tx_byte_sel == 2'd3) begin
                    gmii_txd <= ip_head[cnt][7:0];  
                    if(cnt == 5'd6) begin
                        skip_en <= 1'b1;   
                        cnt <= 5'd0;
                    end   
                    else
                        cnt <= cnt + 5'd1;  
                end        
            end
           st_tx_data  : begin                           //发送数据
                crc_en <= 1'b1;
                gmii_tx_en <= 1'b1;
                tx_byte_sel <= tx_byte_sel + 2'd1;  
                if(tx_byte_sel == 1'b0)
                    gmii_txd <= tx_data[31:24];
                else if(tx_byte_sel == 2'd1)
                    gmii_txd <= tx_data[23:16];                  
                else if(tx_byte_sel == 2'd2) begin
                    gmii_txd <= tx_data[15:8];   
                    if(data_cnt != tx_data_num - 16'd2)
                        tx_req <= 1'b1;  
                end
                else if(tx_byte_sel == 2'd3)
                    gmii_txd <= tx_data[7:0];   
                if(data_cnt < tx_data_num - 16'd1)
                    data_cnt <= data_cnt + 16'd1;                        
                else if(data_cnt == tx_data_num - 16'd1)begin
                    //如果发送的有效数据少于18个字节,在后面填补充位
                    //补充的值为最后一次发送的有效数据
                    tx_req <= 1'b0;
                    if(data_cnt + real_add_cnt < real_tx_data_num - 16'd1)
                        real_add_cnt <= real_add_cnt + 5'd1;  
                    else begin
                        skip_en <= 1'b1;
                        data_cnt <= 16'd0;
                        real_add_cnt <= 5'd0;
                        tx_byte_sel <= 2'd0;                        
                    end   
                    if(real_add_cnt > 0) begin
                        gmii_txd <= 8'd0;
                    end   
                end   
            end   
            st_crc      : begin                          //发送CRC校验值
                gmii_tx_en <= 1'b1;
                tx_byte_sel <= tx_byte_sel + 2'd1;
                if(tx_byte_sel == 2'd0)
                    gmii_txd <= {~crc_next[0], ~crc_next[1], ~crc_next[2],~crc_next[3],
                                 ~crc_next[4], ~crc_next[5], ~crc_next[6],~crc_next[7]};
                else if(tx_byte_sel == 2'd1)
                    gmii_txd <= {~crc_data[16], ~crc_data[17], ~crc_data[18],~crc_data[19],
                                 ~crc_data[20], ~crc_data[21], ~crc_data[22],~crc_data[23]};
                else if(tx_byte_sel == 2'd2) begin
                    gmii_txd <= {~crc_data[8], ~crc_data[9], ~crc_data[10],~crc_data[11],
                                 ~crc_data[12], ~crc_data[13], ~crc_data[14],~crc_data[15]};                              
                end
                else if(tx_byte_sel == 2'd3) begin
                    gmii_txd <= {~crc_data[0], ~crc_data[1], ~crc_data[2],~crc_data[3],
                                 ~crc_data[4], ~crc_data[5], ~crc_data[6],~crc_data[7]};  
                    tx_done_t <= 1'b1;
                    skip_en <= 1'b1;
                end                                   
            end                          
            default :;  
        endcase                                             
    end
end            



//发送完成信号及crc值复位信号
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) begin
        tx_done <= 1'b0;
        crc_clr <= 1'b0;
    end
    else
        begin
        tx_done <= tx_done_t;
        crc_clr <= tx_done_t;
    end
end

endmodule









网口调试助手截图

网口调试助手截图
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

1979

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5520
金钱
5520
注册时间
2018-10-21
在线时间
1561 小时
发表于 2022-1-14 10:53:06 | 显示全部楼层
打开wireshark抓包软件看看,包有没有丢
回复 支持 反对

使用道具 举报

11

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2017-8-17
在线时间
50 小时
 楼主| 发表于 2022-1-14 16:03:43 | 显示全部楼层
QinQZ 发表于 2022-1-14 10:53
打开wireshark抓包软件看看,包有没有丢

有丢包,有实测过FPGA+千兆网的实际速率能达多少吗?
回复 支持 反对

使用道具 举报

11

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2017-8-17
在线时间
50 小时
 楼主| 发表于 2022-1-14 17:48:02 | 显示全部楼层
QinQZ 发表于 2022-1-14 10:53
打开wireshark抓包软件看看,包有没有丢

代码改了一下,包之间不加延时了。使用wireshark抓包工具抓包测试发现速率可达600Mbit/s。不知还有没有可能更快。还是说FPGA+千兆网PHY的极限速率就是600M左右了?
回复 支持 反对

使用道具 举报

3

主题

1979

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5520
金钱
5520
注册时间
2018-10-21
在线时间
1561 小时
发表于 2022-1-17 09:49:33 | 显示全部楼层
lindaoyou 发表于 2022-1-14 17:48
代码改了一下,包之间不加延时了。使用wireshark抓包工具抓包测试发现速率可达600Mbit/s。不知还有没有可 ...

不止,这个可以大致算一下,带宽额外的开销就是帧间隔,以太网帧头,IP首部,UDP首部这些;如果单次按照最大字节传输,速率应该能到900Mbps+
回复 支持 反对

使用道具 举报

11

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2017-8-17
在线时间
50 小时
 楼主| 发表于 2022-1-17 16:00:59 | 显示全部楼层
QinQZ 发表于 2022-1-17 09:49
不止,这个可以大致算一下,带宽额外的开销就是帧间隔,以太网帧头,IP首部,UDP首部这些;如果单次按照 ...

总结一下FPGA实现千兆网的事。
1、实测速率可以达到900多Mbit/s
2、使用网络调试助手接收数据来算是不行的,网络调试数据收数据有问题,速率一高数据就会丢。
3、每个包之间要加延时,我使用40ns延时,也就是5个时钟周期。
4、使用Wireshark可以准确测到UDP速率。
IMG_20220114_101801.jpg
回复 支持 反对

使用道具 举报

11

主题

34

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2017-8-17
在线时间
50 小时
 楼主| 发表于 2022-1-17 16:14:08 | 显示全部楼层
图发错了,补充一下
46947941.jpg
回复 支持 反对

使用道具 举报

3

主题

1979

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5520
金钱
5520
注册时间
2018-10-21
在线时间
1561 小时
发表于 2022-1-19 09:08:36 | 显示全部楼层
lindaoyou 发表于 2022-1-17 16:00
总结一下FPGA实现千兆网的事。
1、实测速率可以达到900多Mbit/s
2、使用网络调试助手接收数据来算是不 ...

网口助手接收大量数据时,容易卡死
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-10-4 00:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表