在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 65228|回复: 116

[原创] 千兆以太网 TCP, UDP协议, FPGA实现

[复制链接]
发表于 2016-2-1 14:37:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 eebinqiu 于 2016-2-1 16:06 编辑

目前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
发表于 2016-2-2 08:48:28 | 显示全部楼层
顶,支持楼主
发表于 2016-2-2 09:41:41 | 显示全部楼层
本帖最后由 whz7783478 于 2016-2-2 09:56 编辑

可惜UDP会丢包,如果是TCP就好了楼主的CPU是macroblaze的吗?还是外置的ARM?
 楼主| 发表于 2016-2-2 16:29:21 | 显示全部楼层
回复 3# whz7783478


   不带cpu,都是Verilog写的
 楼主| 发表于 2016-2-3 13:48:13 | 显示全部楼层
本帖最后由 eebinqiu 于 2016-2-11 15:23 编辑

quartus综合结果:
syn_quartus.jpg
有偿提供IP核,需要的朋友,请用站内信
发表于 2016-2-16 11:16:44 | 显示全部楼层
回复 5# eebinqiu


   楼主你好,有没有actel FPGA使用的以太网IP?
 楼主| 发表于 2016-2-16 12:54:59 | 显示全部楼层
回复 6# YMXWENQING


   有的,代码是通用的
发表于 2016-2-16 14:02:38 | 显示全部楼层
本帖最后由 YMXWENQING 于 2016-2-16 14:21 编辑

回复 7# eebinqiu


    你好,如果只需要MAC的代码,价钱如何,另外能否转成vhdl或者verilog
 楼主| 发表于 2016-2-16 14:53:38 | 显示全部楼层
本帖最后由 eebinqiu 于 2016-2-17 13:11 编辑

回复 8# YMXWENQING


   目前只有SV版的, 如果你需要Verilog,我帮你改好, 具体谈加QQ:1517642772
发表于 2016-2-16 16:03:56 | 显示全部楼层
不错,新项目需要这个
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条


小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-11-29 03:35 , Processed in 0.030311 second(s), 9 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表