你的位置:EETOP 赛灵思(Xilinx) 社区 >> >> 全部 >> 详细内容

千兆以太网 TCP, UDP协议, FPGA实现

发布者:jackzhang 时间:2016-05-30 21:20:05

目前TCP协议大多由cpu跑代码实现, 这次用FPGA的纯逻辑实现 , System Verilog编写,

下面给大家粗略讲一下我的实现方法,

下面是工程的示意图.

tcp框图.jpg

这个工程由几部分组成, 外部使用了88e1111千兆以太网phy。FPGA内部有几个大的模块,

顶层模块:

  
  1. //////////////////////////////////////////////////////////////////////  
  2.     ////                                                              ////  
  3.     ////  tcpip_hw                                                    ////  
  4.     ////                                                              ////  
  5.     ////  Description                                                 ////  
  6.     ////      top module                                              ////  
  7.     ////                                                              ////  
  8.     ////  Author(s):                                                  ////  
  9.     ////      - bin qiu, qiubin@opencores.org or  chat1@126.com       ////  
  10.     ////                                                              ////  
  11.     ////                   Copyright (C) 2015                         ////  
  12.     //////////////////////////////////////////////////////////////////////  
  13.     `include "tcpip_hw_defines.sv"  
  14.       
  15.     module tcpip_hw(      
  16.         input clk,  
  17.         input rst_n,  
  18.          
  19.         output mdc,  
  20.         inout  mdio,  
  21.         output phy_rst_n,  
  22.         output is_link_up,  
  23.       
  24.         input [7:0] rx_data,  
  25.         output logic [7:0] tx_data,  
  26.       
  27.         input rx_clk,  
  28.         input rx_data_valid,  
  29.         output logic gtx_clk,  
  30.         input  tx_clk,   
  31.         output logic tx_en,  
  32.          
  33. //user interface
  34.         input [7:0] wr_data,   
  35.         input wr_clk,   
  36.         input wr_en,   
  37.         output wr_full,   
  38.         
  39.         output [7:0] rd_data,   
  40.         input rd_clk,   
  41.         input rd_en,   
  42.         output rd_empty  
  43.     );  
  44.       
  45.     wire clk8;  
  46.     wire clk50;  
  47.     wire clk125;  
  48.     wire clk125out;  
  49.     wire is_1000m;  
  50.     logic eth_mode;  
  51.       
  52.       
  53.     always @(posedge clk50)  
  54.         eth_mode <= is_1000m;  
  55.          
  56.     assign gtx_clk = clk125out;  
  57.       
  58.       
  59.     pll pll_inst(  
  60.         .inclk0(clk),  
  61.         .c0(clk50),  
  62.         .c1(clk125out),  
  63.         .c2(clk8)  
  64.     );  
  65.       
  66.     wire mdio_out;  
  67.     wire mdio_oe;  
  68.     wire reset_n;  
  69.       
  70.     assign mdio = mdio_oe == 1'b1 ? mdio_out : 1'bz;   
  71.     rst_ctrl rst_ctrl_inst(  
  72.         .ext_rst(rst_n),  
  73.         .rst(reset_n),  
  74.         .clk(clk50)   
  75.     );  
  76.       
  77.     wire is_100m;  
  78.     wire is_10m;  
  79.       
  80.     wire [7:0] tse_addr;  
  81.     wire tse_wr;  
  82.     wire [31:0] tse_wr_data;  
  83.     wire tse_rd;  
  84.     wire [31:0] tse_rd_data;  
  85.     wire tse_busy;  
  86.       
  87.       
  88.     headers_if if_headers_rx(clk50);  
  89.     headers_if if_headers_tx(clk50);  
  90.     ff_tx_if if_tx(clk50);  
  91.     ff_rx_if if_rx(clk50);  
  92.       
  93.     frame_type_t rx_type;  
  94.     frame_type_t tx_type;  
  95.       
  96.     logic rx_done;  
  97.     logic [31:0] data_recv;  
  98.     logic [15:0] data_recv_len;  
  99.     logic data_recv_valid;  
  100.     logic data_recv_start;  
  101.     logic rx_done_clear;  
  102.     u32_t cur_ripaddr;  
  103.     u16_t cur_rport;  
  104.     u16_t rx_header_checksum;  
  105.     logic need_ack;  
  106.     logic [7:0] flags;  
  107.       
  108.     logic tx_start;  
  109.     logic [13:0] tx_dword_count;  
  110.     logic fifo_rdreq;  
  111.     logic [31:0] fifo_q;  
  112.     logic fifo_empty;  
  113.     logic pkt_send_eop;  
  114.     logic [15:0] data_send_len;  
  115.       
  116.     logic [10:0] wr_addr_synced;  
  117.     rx_ram_in_if if_rx_ram_in();  
  118.     rx_ram_out_if if_rx_ram_out();  
  119.     tx_ram_out_if if_tx_ram_out();  
  120.     tx_ram_in_if if_tx_ram_in();  
  121.       
  122.     logic [31:0] local_ipaddr;  
  123.     logic [31:0] remote_ipaddr;  
  124.     logic [31:0] remote_port_local_port;  
  125.     logic [1:0] op_mode;  
  126.     logic init_done;  
  127.     simple_mac_top simple_mac_top(   
  128.         .clk(clk50),  
  129.         .rst_n(reset_n),  
  130.          
  131.         .mdc(mdc),  
  132.         .mdio_in(mdio),  
  133.         .mdio_out(mdio_out),  
  134.         .mdio_oe(mdio_oe),  
  135.         .phy_rst_n(phy_rst_n),  
  136.         .eth_mode(eth_mode),  
  137.          
  138.         .rx_data(rx_data[7:0]),  
  139.         .tx_data(tx_data[7:0]),  
  140.         .rx_clk(rx_clk),  
  141.         .tx_clk(tx_clk),  
  142.         .clk125out(clk125out),  
  143.         .rx_data_valid(rx_data_valid),  
  144.         .tx_en(tx_en),  
  145.         .reg_addr(tse_addr),  
  146.         .reg_wr(tse_wr),  
  147.         .reg_wr_data(tse_wr_data),  
  148.         .reg_rd(tse_rd),  
  149.         .reg_rd_data(tse_rd_data),  
  150.         .reg_busy(tse_busy),  
  151.          
  152.         .ff_rx_clk(clk50),  
  153.         .ff_rx_data(if_rx.ff_rx_data),  
  154.         .ff_rx_eop(if_rx.ff_rx_eop),  
  155.         .ff_rx_sop(if_rx.ff_rx_sop),  
  156.         .rx_err(if_rx.rx_err),  
  157.         .ff_rx_dval(if_rx.ff_rx_dval),  
  158.         .ff_rx_rdy(if_rx.ff_rx_rdy),  
  159.       
  160.         .ff_tx_clk(clk50),  
  161.         .ff_tx_data(if_tx.ff_tx_data),  
  162.         .ff_tx_eop(if_tx.ff_tx_eop),  
  163.         .ff_tx_sop(if_tx.ff_tx_sop),  
  164.         .ff_tx_wren(if_tx.ff_tx_wren),  
  165.         .ff_tx_rdy(if_tx.ff_tx_rdy),  
  166.         .*  
  167.     );  
  168.       
  169.       
  170.     data_source data_source_inst(  
  171.         .rst_n(reset_n),  
  172.         .wr_data(wr_data),  
  173.         .wr_clk(wr_clk),  
  174.         .wr_en(wr_en),  
  175.         .wr_full(wr_full),  
  176.       
  177.         .rd_data(rd_data),  
  178.         .rd_clk(rd_clk),  
  179.         .rd_en(rd_en),  
  180.         .rd_empty(rd_empty),  
  181.          
  182.         .*  
  183.     );  
  184.       
  185.     rx_ram rx_ram_inst(  
  186.         .rst_n(reset_n),  
  187.         .*  
  188.     );  
  189.       
  190.     tx_ram tx_ram_inst(  
  191.         .rst_n(reset_n),  
  192.         .overflow_flag(),  
  193.         .in_flush(),  
  194.         .*  
  195.     );  
  196.       
  197.     mac_config mac_config_inst (  
  198.         .clk(clk50),  
  199.         .rst_n(reset_n),  
  200.         .*  
  201.     );  
  202.       
  203.     assign pkt_send_eop = if_tx.ff_tx_eop;  
  204.     logic [3:0] next_parse_state;  
  205.       
  206.       
  207.     mac_rx_path mac_rx_path_inst(  
  208.         .rst_n(reset_n),  
  209.         .*  
  210.     );  
  211.       
  212.     mac_tx_path  mac_tx_path_inst (  
  213.         .rst_n(reset_n),  
  214.          .next_state(),  
  215.         .*  
  216.     );  
  217.       
  218.     eth_fsm eth_fsm_inst(  
  219.         .clk(clk50),  
  220.         .rst_n(reset_n),  
  221.         .state_counter(),  
  222.        .*  
  223.     );  
  224.       
  225.     endmodule
复制代码



      1.与外部phy芯片通信的模块,simple_mac模块。主要功能是通过mdio配置phy, 给发送帧打包(加入preamble,padding和crc32),和接收帧解包。 下面是顶层代码:   
  1. //////////////////////////////////////////////////////////////////////  
  2.     ////                                                              ////  
  3.     ////  simple_mac_top                                              ////  
  4.     ////                                                              ////  
  5.     ////  Description                                                 ////  
  6.     ////      top module of simple mac                                ////  
  7.     ////                                                              ////  
  8.     ////  Author(s):                                                  ////  
  9.     ////      - bin qiu, qiubin@opencores.org or  chat1@126.com       ////  
  10.     ////                                                              ////  
  11.     ////                   Copyright (C) 2015                         ////  
  12.     //////////////////////////////////////////////////////////////////////  
  13.       
  14.       
  15.     module simple_mac_top(   
  16.         input clk,  
  17.         input rst_n,  
  18.          
  19.         output mdc,  
  20.         input  mdio_in,  
  21.         output mdio_out,  
  22.         output mdio_oe,  
  23.         output phy_rst_n,  
  24.       
  25.         input [7:0] rx_data,  
  26.         output logic [7:0] tx_data,  
  27.          
  28.         input eth_mode,  
  29.         input rx_clk,  
  30.         input tx_clk,  
  31.         input clk125out,  
  32.         output tx_en,  
  33.         input  rx_data_valid,  
  34.       
  35.         input [7:0] reg_addr,  
  36.         input reg_wr,  
  37.         input [31:0] reg_wr_data,  
  38.         input reg_rd,  
  39.         output [31:0] reg_rd_data,  
  40.         output reg_busy,  
  41.          
  42.         input  ff_rx_clk,  
  43.         output [31:0] ff_rx_data,  
  44.         output ff_rx_eop,  
  45.         output ff_rx_sop,  
  46.         output rx_err,  
  47.         output ff_rx_dval,  
  48.         input  ff_rx_rdy,  
  49.       
  50.         input ff_tx_clk,  
  51.         input [31:0] ff_tx_data,  
  52.         input ff_tx_eop,  
  53.         input ff_tx_sop,  
  54.         input ff_tx_wren,  
  55.         output ff_tx_rdy  
  56.     );  
  57.     assign phy_rst_n = rst_n;  
  58.       
  59.     wire [7:0] rx_data_mac;  
  60.     wire rx_data_valid_mac;  
  61.     wire rx_sop_mac;  
  62.     wire tx_data_valid_mac;  
  63.     wire [7:0] tx_data_mac;  
  64.       
  65.       
  66.     wire [31:0] ff_tx_data0;  
  67.     wire ff_tx_eop0;  
  68.     wire ff_tx_sop0;  
  69.     wire ff_tx_wren0;  
  70.       
  71.     wire [31:0] ff_rx_data0;  
  72.     wire ff_rx_eop0;  
  73.     wire ff_rx_sop0;  
  74.     wire ff_rx_dval0;  
  75.       
  76.     wire tx_data_en;  
  77.       
  78.     tx_header_align32 tx_header_align32_inst(  
  79.         .ff_tx_clk(ff_tx_clk),  
  80.         .rst_n(rst_n),  
  81.         .ff_tx_data0(ff_tx_data),  
  82.         .ff_tx_eop0(ff_tx_eop),  
  83.         .ff_tx_sop0(ff_tx_sop),  
  84.         .ff_tx_wren0(ff_tx_wren),  
  85.       
  86.         .ff_tx_data(ff_tx_data0),  
  87.         .ff_tx_eop(ff_tx_eop0),  
  88.         .ff_tx_sop(ff_tx_sop0),  
  89.         .ff_tx_wren(ff_tx_wren0)  
  90.     );  
  91.       
  92.       
  93.     rx_header_align32 rx_header_align32_inst(  
  94.         .ff_rx_clk(ff_rx_clk),  
  95.         .rst_n(rst_n),  
  96.         .ff_rx_data0(ff_rx_data0),  
  97.         .ff_rx_eop0(ff_rx_eop0),  
  98.         .ff_rx_sop0(ff_rx_sop0),  
  99.         .ff_rx_dval0(ff_rx_dval0),  
  100.       
  101.         .ff_rx_data(ff_rx_data),  
  102.         .ff_rx_eop(ff_rx_eop),  
  103.         .ff_rx_sop(ff_rx_sop),  
  104.         .ff_rx_dval(ff_rx_dval)  
  105.     );  
  106.     wire mac_tx_clk;  
  107.       
  108.     assign mac_tx_clk = clk125out;  
  109.       
  110.     simple_mac_rx_gmii rx_gmii_inst(  
  111.         .rx_clk(rx_clk),  
  112.         .rst_n(rst_n),  
  113.         .eth_mode(eth_mode),  
  114.         .rx_data(rx_data),  
  115.         .rx_data_valid(rx_data_valid),  
  116.       
  117.         .rx_data_mac(rx_data_mac),  
  118.         .rx_data_valid_mac(rx_data_valid_mac),  
  119.         .rx_sop_mac(rx_sop_mac)  
  120.     );  
  121.       
  122.     simple_mac_tx_gmii gmii_tx_inst(  
  123.         .rst_n(rst_n),  
  124.         .eth_mode(eth_mode),  
  125.         .tx_data_mac(tx_data_mac),  
  126.         .tx_data_valid_mac(tx_data_valid_mac),  
  127.         .tx_data_en(tx_data_en),  
  128.       
  129.         .tx_clk(mac_tx_clk),  
  130.         .tx_en(tx_en),  
  131.         .tx_data(tx_data)  
  132.     );  
  133.       
  134.     logic [47:0] mac_addr;  
  135.     simple_mac_rx_path simple_mac_rx_path_inst(  
  136.         .rx_clk(rx_clk),  
  137.         .rst_n(rst_n),  
  138.         .mac_addr(mac_addr),  
  139.         .rx_data_mac(rx_data_mac),  
  140.         .rx_data_valid_mac(rx_data_valid_mac),  
  141.         .rx_sop_mac(rx_sop_mac),  
  142.       
  143.        .ff_rx_clk(ff_rx_clk),  
  144.        .ff_rx_data(ff_rx_data0),  
  145.        .ff_rx_eop(ff_rx_eop0),  
  146.        .ff_rx_sop(ff_rx_sop0),  
  147.        .rx_err(rx_err),  
  148.        .ff_rx_dval(ff_rx_dval0),  
  149.        .ff_rx_rdy(ff_rx_rdy)  
  150.     );  
  151.       
  152.     simple_mac_tx_path simple_mac_tx_path_inst(  
  153.         .ff_tx_clk(ff_tx_clk),  
  154.         .rst_n(rst_n),  
  155.         .eth_mode(eth_mode),  
  156.         .ff_tx_data(ff_tx_data0),  
  157.         .ff_tx_eop(ff_tx_eop0),  
  158.         .ff_tx_sop(ff_tx_sop0),  
  159.         .ff_tx_wren(ff_tx_wren0),  
  160.         .ff_tx_rdy(ff_tx_rdy),  
  161.       
  162.         .tx_clk_mac(mac_tx_clk),  
  163.         .tx_data_mac(tx_data_mac),  
  164.         .tx_data_valid_mac(tx_data_valid_mac),  
  165.         .tx_data_en(tx_data_en),  
  166.         .pkt_send_num()  
  167.       
  168.     );  
  169.       
  170.     wire mdio_busy;  
  171.     wire [15:0] mdio_rd_data;  
  172.     simple_mac_phy_mdio phy_mdio(  
  173.         .clk(clk),  
  174.         .rst_n(rst_n),  
  175.         .mdc(mdc),  
  176.         .mdin(mdio_in),  
  177.         .mdout(mdio_out),  
  178.         .mdoe(mdio_oe),  
  179.       
  180.         .phy_addr(5'b10000),  
  181.         .data_in(reg_wr_data[15:0]),  
  182.         .reg_addr(reg_addr),  
  183.         .wr(reg_wr),  
  184.         .rd(reg_rd),  
  185.         .data_out(mdio_rd_data),  
  186.         .busy(mdio_busy)      
  187.     );  
  188.       
  189.     wire [31:0] regs_rd_data;  
  190.     wire regs_busy;  
  191.     simple_mac_regs simple_mac_regs_inst(  
  192.         .clk(clk),  
  193.         .rst_n(rst_n),  
  194.         .data_in(reg_wr_data),  
  195.         .reg_addr(reg_addr),  
  196.         .wr(reg_wr),  
  197.         .rd(reg_rd),  
  198.         .data_out(regs_rd_data),  
  199.         .busy(regs_busy),  
  200.       
  201.         .mac_addr(mac_addr),  
  202.         .*  
  203.     );  
  204.       
  205.     simple_mac_bus_arb simple_mac_bus_arb_inst(  
  206.         .reg_addr(reg_addr),      
  207.         .mdio_busy(mdio_busy),  
  208.         .mdio_rd_data(mdio_rd_data),  
  209.         .regs_busy(regs_busy),  
  210.         .regs_rd_data(regs_rd_data),  
  211.         .reg_busy(reg_busy),  
  212.         .reg_rd_data(reg_rd_data)  
  213.     );  
  214.       
  215.       
  216.     endmodule
复制代码

2.mac_config

这个模块主要是配置phy芯片寄存器的。


3.Rx Path

这个模块负责从simple_mac接收数据,然后提交给eth_fsm的。 下面是接口列表.

  1. input rst_n,  
  2.     ff_rx_if.s if_rx,  
  3.     headers_if if_headers_rx,   
  4.     output frame_type_t rx_type,  
  5.     output logic rx_done,  
  6.       
  7.     output logic [31:0] data_recv,  
  8.     output logic data_recv_start,  
  9.     output logic data_recv_valid,  
  10.     output logic [15:0] data_recv_len,  
  11.     output u32_t cur_ripaddr,  
  12.     output u16_t cur_rport,  
  13.       
  14.     input rx_done_clear,  
  15.       
  16.     input [31:0] local_ipaddr,  
  17.     input [31:0] remote_port_local_port
复制代码
   

接口列表里有2个interface,

if_rx是与simple_mac连接的接口。

if_headers_rx是保存各种header并提供给eth_fsm的,如mac_header, arp_header,ip_header,udp_header,tcp_header。

rx_done是一帧接收完的信号并提供给eth_fsm。

中间一段用来从一帧中提取数据并提供给eth_fsm 。

下面是配置ip地址和收发端口号的。


4.Tx Path

这个模块从eth_fsm取得数据和各种header,并发送给simple_mac, 下面是接口

  1. input rst_n,  
  2.     ff_tx_if.s if_tx,  
  3.     headers_if if_headers_tx,  
  4.     input frame_type_t tx_type,  
  5.     input tx_start,  
  6.     input [13:0] tx_dword_count,  
  7.     output logic fifo_rdreq,  
  8.     input [31:0] fifo_q
复制代码

其中if_tx是与simple_mac的接口, if_headers_tx是从eth_fsm来的各种header,

tx_type是帧的类型,目前支持ARP, ICMP,TCP,UDP。

tx_start是一帧传输开始的信号。

tx_dword_count是发送的字节数除以4 。

fifo_rdreq和fifo_q是从eth_fsm来的数据。


5.eth_fsm

这是整个工程的核心, 是处理协议的状态机和控制数据的流动,下面是接口

  
  1. input clk,  
  2.     input rst_n,  
  3.     input is_link_up,  
  4.       
  5.     headers_if if_headers_rx,  
  6.     input frame_type_t rx_type,  
  7.     input rx_done,  
  8.       
  9.     headers_if if_headers_tx,  
  10.     output frame_type_t tx_type,  
  11.     output logic tx_start,  
  12.       
  13.     input [31:0] data_recv,  
  14.     input [15:0] data_recv_len,  
  15.     input data_recv_valid,  
  16.     input data_recv_start,  
  17.     output logic rx_done_clear,  
  18.     input u32_t cur_ripaddr,  
  19.     input u16_t cur_rport,  
  20.     rx_ram_in_if.m if_rx_ram_in,  
  21.     tx_ram_out_if.m if_tx_ram_out,  
  22.     input [31:0] remote_port_local_port,  
  23.     input [31:0] local_ipaddr,  
  24.     input fifo_rdreq,  
  25.     output [31:0] fifo_q,  
  26.     input pkt_send_eop,  
  27.       
  28.     output logic [13:0]  tx_dword_count,  
  29.     output logic init_done
复制代码

由于这个模块过于复杂,就不介绍了。

6.data_source

这个模块提供了与用户模块的接口        
  1. input rst_n,  
  2.         input init_done,  
  3.       
  4.         input [7:0] wr_data,  
  5.         input wr_clk,  
  6.         input wr_en,  
  7.         output wr_full,  
  8.       
  9.         output [7:0] rd_data,  
  10.         input rd_clk,  
  11.         input rd_en,  
  12.         output rd_empty,  
  13.          
  14.         tx_ram_in_if.m if_tx_ram_in,  
  15.         rx_ram_out_if.s if_rx_ram_out  
复制代码

其中wr开头和rd开头的都是对外提供的fifo接口,  分别用来写和读内部的发送FIFO和接收FIFO.


目前实现情况

目前udp协议可以基本全速运行,但是有丢包的情况,需要有个确认机制。

tcp协议只实现了最基本的功能,能够通信。窗口管理和慢启动,拥塞避免等特性还在完善中,速度只能达到200多M。


对这个工程的介绍就到这里了,希望对大家有用。


udp_speed.jpg (325.21 KB)

udp_speed.jpg

最新课程

  • 深入浅出玩儿转FPGA

    本视频基于Xilinx公司的Artix-7FPGA器件以及各种丰富的入门和进阶外设,提供了一些典型的工程实例,帮助读者从FPGA基础知识、逻辑设计概念

  • 从零开始大战FPGA基础篇

    本课程为“从零开始大战FPGA”系列课程的基础篇。课程通俗易懂、逻辑性强、示例丰富,课程中尤其强调在设计过程中对“时序”和“逻辑”的把控,以及硬件描述语言与硬件电路相对应的“

  • Verilog基础及典型数字

    课程中首先会给大家讲解在企业中一般数字电路从算法到流片这整个过程中会涉及到哪些流程,都分别使用什么工具,以及其中每个流程都分别做了