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



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

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

下面是工程的示意图.

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

顶层模块:

[plain]   view plain  copy
  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. er 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),和接收帧解包。 下面是顶层代码:
[plain]   view plain  copy
  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的。 下面是接口列表.

[plain]   view plain  copy
  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,   

接口列表里有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, 下面是接口

[plain]   view plain  copy
  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

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

[plain]   view plain  copy
  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

这个模块提供了与用户模块的接口  
[plain]   view plain  copy
  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    
  16. )    

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


目前实现情况

目前udp协议可以基本全速运行,由于全速达到了100MB/s以上,如果处理速度慢,会有丢包的情况。


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


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

udp版本可以是开源的,但是商用需要license费。

tcp版本不开源,也是收费的。

需要的朋友可联系我qq:1517642772

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值