千兆以太网 TCP, UDP协议, FPGA实现
2016-01-30 23:03
513 查看
目前TCP协议大多由cpu跑代码实现, 这次用FPGA的纯逻辑实现 , System Verilog编写,
下面给大家粗略讲一下我的实现方法,
下面是工程的示意图.
这个工程由几部分组成, 外部使用了88e1111千兆以太网phy。FPGA内部有几个大的模块,
顶层模块:
1.与外部phy芯片通信的模块,simple_mac模块。主要功能是通过mdio配置phy, 给发送帧打包(加入preamble,padding和crc32),和接收帧解包。 下面是顶层代码:
2.mac_config
这个模块主要是配置phy芯片寄存器的。
3.Rx Path
这个模块负责从simple_mac接收数据,然后提交给eth_fsm的。 下面是接口列表.
接口列表里有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, 下面是接口
其中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
这是整个工程的核心, 是处理协议的状态机和控制数据的流动,下面是接口
由于这个模块过于复杂,就不介绍了。
6.data_source
这个模块提供了与用户模块的接口
其中wr开头和rd开头的都是对外提供的fifo接口, 分别用来写和读内部的发送FIFO和接收FIFO.
目前实现情况
目前udp协议可以基本全速运行,由于全速达到了100MB/s以上,如果处理速度慢,会有丢包的情况。
目前tcp协议只实现了最基本的功能,能够通信。窗口管理和慢启动,拥塞避免等特性还在完善中,速度只能达到200多M。
对这个工程的介绍就到这里了,希望对大家有用。
udp版本可以是开源的,但是商用需要license费。
tcp版本不开源,也是收费的。
需要的朋友可联系我qq:1517642772
下面给大家粗略讲一下我的实现方法,
下面是工程的示意图.
这个工程由几部分组成, 外部使用了88e1111千兆以太网phy。FPGA内部有几个大的模块,
顶层模块:
////////////////////////////////////////////////////////////////////// //// //// //// tcpip_hw //// //// //// //// Description //// //// top module //// //// //// //// Author(s): //// //// - bin qiu, qiubin@opencores.org or chat1@126.com //// //// //// //// Copyright (C) 2015 //// ////////////////////////////////////////////////////////////////////// `include "tcpip_hw_defines.sv" module tcpip_hw( input clk, input rst_n, output mdc, inout mdio, output phy_rst_n, output is_link_up, input [7:0] rx_data, output logic [7:0] tx_data, input rx_clk, input rx_data_valid, output logic gtx_clk, input tx_clk, output logic tx_en, //user interface input [7:0] wr_data, input wr_clk, input wr_en, output wr_full, output [7:0] rd_data, input rd_clk, input rd_en, output rd_empty ); wire clk8; wire clk50; wire clk125; wire clk125out; wire is_1000m; logic eth_mode; always @(posedge clk50) eth_mode <= is_1000m; assign gtx_clk = clk125out; pll pll_inst( .inclk0(clk), .c0(clk50), .c1(clk125out), .c2(clk8) ); wire mdio_out; wire mdio_oe; wire reset_n; assign mdio = mdio_oe == 1'b1 ? mdio_out : 1'bz; rst_ctrl rst_ctrl_inst( .ext_rst(rst_n), .rst(reset_n), .clk(clk50) ); wire is_100m; wire is_10m; wire [7:0] tse_addr; wire tse_wr; wire [31:0] tse_wr_data; wire tse_rd; wire [31:0] tse_rd_data; wire tse_busy; headers_if if_headers_rx(clk50); headers_if if_headers_tx(clk50); ff_tx_if if_tx(clk50); ff_rx_if if_rx(clk50); frame_type_t rx_type; frame_type_t tx_type; logic rx_done; logic [31:0] data_recv; logic [15:0] data_recv_len; logic data_recv_valid; logic data_recv_start; logic rx_done_clear; u32_t cur_ripaddr; u16_t cur_rport; u16_t rx_header_checksum; logic need_ack; logic [7:0] flags; logic tx_start; logic [13:0] tx_dword_count; logic fifo_rdreq; logic [31:0] fifo_q; logic fifo_empty; logic pkt_send_eop; logic [15:0] data_send_len; logic [10:0] wr_addr_synced; rx_ram_in_if if_rx_ram_in(); rx_ram_out_if if_rx_ram_out(); tx_ram_out_if if_tx_ram_out(); tx_ram_in_if if_tx_ram_in(); logic [31:0] local_ipaddr; logic [31:0] remote_ipaddr; logic [31:0] remote_port_local_port; logic [1:0] op_mode; logic init_done; simple_mac_top simple_mac_top( .clk(clk50), .rst_n(reset_n), .mdc(mdc), .mdio_in(mdio), .mdio_out(mdio_out), .mdio_oe(mdio_oe), .phy_rst_n(phy_rst_n), .eth_mode(eth_mode), .rx_data(rx_data[7:0]), .tx_data(tx_data[7:0]), .rx_clk(rx_clk), .tx_clk(tx_clk), .clk125out(clk125out), .rx_data_valid(rx_data_valid), .tx_en(tx_en), .reg_addr(tse_addr), .reg_wr(tse_wr), .reg_wr_data(tse_wr_data), .reg_rd(tse_rd), .reg_rd_data(tse_rd_data), .reg_busy(tse_busy), .ff_rx_clk(clk50), .ff_rx_data(if_rx.ff_rx_data), .ff_rx_eop(if_rx.ff_rx_eop), .ff_rx_sop(if_rx.ff_rx_sop), .rx_err(if_rx.rx_err), .ff_rx_dval(if_rx.ff_rx_dval), .ff_rx_rdy(if_rx.ff_rx_rdy), .ff_tx_clk(clk50), .ff_tx_data(if_tx.ff_tx_data), .ff_tx_eop(if_tx.ff_tx_eop), .ff_tx_sop(if_tx.ff_tx_sop), .ff_tx_wren(if_tx.ff_tx_wren), .ff_tx_rdy(if_tx.ff_tx_rdy), .* ); data_source data_source_inst( .rst_n(reset_n), .wr_data(wr_data), .wr_clk(wr_clk), .wr_en(wr_en), .wr_full(wr_full), .rd_data(rd_data), .rd_clk(rd_clk), .rd_en(rd_en), .rd_empty(rd_empty), .* ); rx_ram rx_ram_inst( .rst_n(reset_n), .* ); tx_ram tx_ram_inst( .rst_n(reset_n), .overflow_flag(), .in_flush(), .* ); mac_config mac_config_inst ( .clk(clk50), .rst_n(reset_n), .* ); assign pkt_send_eop = if_tx.ff_tx_eop; logic [3:0] next_parse_state; mac_rx_path mac_rx_path_inst( .rst_n(reset_n), .* ); mac_tx_path mac_tx_path_inst ( .rst_n(reset_n), .next_state(), .* ); eth_fsm eth_fsm_inst( .clk(clk50), .rst_n(reset_n), .state_counter(), .* ); endmodule
1.与外部phy芯片通信的模块,simple_mac模块。主要功能是通过mdio配置phy, 给发送帧打包(加入preamble,padding和crc32),和接收帧解包。 下面是顶层代码:
////////////////////////////////////////////////////////////////////// //// //// //// simple_mac_top //// //// //// //// Description //// //// top module of simple mac //// //// //// //// Author(s): //// //// - bin qiu, qiubin@opencores.org or chat1@126.com //// //// //// //// Copyright (C) 2015 //// ////////////////////////////////////////////////////////////////////// module simple_mac_top( input clk, input rst_n, output mdc, input mdio_in, output mdio_out, output mdio_oe, output phy_rst_n, input [7:0] rx_data, output logic [7:0] tx_data, input eth_mode, input rx_clk, input tx_clk, input clk125out, output tx_en, input rx_data_valid, input [7:0] reg_addr, input reg_wr, input [31:0] reg_wr_data, input reg_rd, output [31:0] reg_rd_data, output reg_busy, input ff_rx_clk, output [31:0] ff_rx_data, output ff_rx_eop, output ff_rx_sop, output rx_err, output ff_rx_dval, input ff_rx_rdy, input ff_tx_clk, input [31:0] ff_tx_data, input ff_tx_eop, input ff_tx_sop, input ff_tx_wren, output ff_tx_rdy ); assign phy_rst_n = rst_n; wire [7:0] rx_data_mac; wire rx_data_valid_mac; wire rx_sop_mac; wire tx_data_valid_mac; wire [7:0] tx_data_mac; wire [31:0] ff_tx_data0; wire ff_tx_eop0; wire ff_tx_sop0; wire ff_tx_wren0; wire [31:0] ff_rx_data0; wire ff_rx_eop0; wire ff_rx_sop0; wire ff_rx_dval0; wire tx_data_en; tx_header_align32 tx_header_align32_inst( .ff_tx_clk(ff_tx_clk), .rst_n(rst_n), .ff_tx_data0(ff_tx_data), .ff_tx_eop0(ff_tx_eop), .ff_tx_sop0(ff_tx_sop), .ff_tx_wren0(ff_tx_wren), .ff_tx_data(ff_tx_data0), .ff_tx_eop(ff_tx_eop0), .ff_tx_sop(ff_tx_sop0), .ff_tx_wren(ff_tx_wren0) ); rx_header_align32 rx_header_align32_inst( .ff_rx_clk(ff_rx_clk), .rst_n(rst_n), .ff_rx_data0(ff_rx_data0), .ff_rx_eop0(ff_rx_eop0), .ff_rx_sop0(ff_rx_sop0), .ff_rx_dval0(ff_rx_dval0), .ff_rx_data(ff_rx_data), .ff_rx_eop(ff_rx_eop), .ff_rx_sop(ff_rx_sop), .ff_rx_dval(ff_rx_dval) ); wire mac_tx_clk; assign mac_tx_clk = clk125out; simple_mac_rx_gmii rx_gmii_inst( .rx_clk(rx_clk), .rst_n(rst_n), .eth_mode(eth_mode), .rx_data(rx_data), .rx_data_valid(rx_data_valid), .rx_data_mac(rx_data_mac), .rx_data_valid_mac(rx_data_valid_mac), .rx_sop_mac(rx_sop_mac) ); simple_mac_tx_gmii gmii_tx_inst( .rst_n(rst_n), .eth_mode(eth_mode), .tx_data_mac(tx_data_mac), .tx_data_valid_mac(tx_data_valid_mac), .tx_data_en(tx_data_en), .tx_clk(mac_tx_clk), .tx_en(tx_en), .tx_data(tx_data) ); logic [47:0] mac_addr; simple_mac_rx_path simple_mac_rx_path_inst( .rx_clk(rx_clk), .rst_n(rst_n), .mac_addr(mac_addr), .rx_data_mac(rx_data_mac), .rx_data_valid_mac(rx_data_valid_mac), .rx_sop_mac(rx_sop_mac), .ff_rx_clk(ff_rx_clk), .ff_rx_data(ff_rx_data0), .ff_rx_eop(ff_rx_eop0), .ff_rx_sop(ff_rx_sop0), .rx_err(rx_err), .ff_rx_dval(ff_rx_dval0), .ff_rx_rdy(ff_rx_rdy) ); simple_mac_tx_path simple_mac_tx_path_inst( .ff_tx_clk(ff_tx_clk), .rst_n(rst_n), .eth_mode(eth_mode), .ff_tx_data(ff_tx_data0), .ff_tx_eop(ff_tx_eop0), .ff_tx_sop(ff_tx_sop0), .ff_tx_wren(ff_tx_wren0), .ff_tx_rdy(ff_tx_rdy), .tx_clk_mac(mac_tx_clk), .tx_data_mac(tx_data_mac), .tx_data_valid_mac(tx_data_valid_mac), .tx_data_en(tx_data_en), .pkt_send_num() ); wire mdio_busy; wire [15:0] mdio_rd_data; simple_mac_phy_mdio phy_mdio( .clk(clk), .rst_n(rst_n), .mdc(mdc), .mdin(mdio_in), .mdout(mdio_out), .mdoe(mdio_oe), .phy_addr(5'b10000), .data_in(reg_wr_data[15:0]), .reg_addr(reg_addr), .wr(reg_wr), .rd(reg_rd), .data_out(mdio_rd_data), .busy(mdio_busy) ); wire [31:0] regs_rd_data; wire regs_busy; simple_mac_regs simple_mac_regs_inst( .clk(clk), .rst_n(rst_n), .data_in(reg_wr_data), .reg_addr(reg_addr), .wr(reg_wr), .rd(reg_rd), .data_out(regs_rd_data), .busy(regs_busy), .mac_addr(mac_addr), .* ); simple_mac_bus_arb simple_mac_bus_arb_inst( .reg_addr(reg_addr), .mdio_busy(mdio_busy), .mdio_rd_data(mdio_rd_data), .regs_busy(regs_busy), .regs_rd_data(regs_rd_data), .reg_busy(reg_busy), .reg_rd_data(reg_rd_data) ); endmodule
2.mac_config
这个模块主要是配置phy芯片寄存器的。
3.Rx Path
这个模块负责从simple_mac接收数据,然后提交给eth_fsm的。 下面是接口列表.
input rst_n, ff_rx_if.s if_rx, headers_if if_headers_rx, output frame_type_t rx_type, output logic rx_done, output logic [31:0] data_recv, output logic data_recv_start, output logic data_recv_valid, output logic [15:0] data_recv_len, output u32_t cur_ripaddr, output u16_t cur_rport, input rx_done_clear, input [31:0] local_ipaddr, 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, 下面是接口
input rst_n, ff_tx_if.s if_tx, headers_if if_headers_tx, input frame_type_t tx_type, input tx_start, input [13:0] tx_dword_count, output logic fifo_rdreq, 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
这是整个工程的核心, 是处理协议的状态机和控制数据的流动,下面是接口
input clk, input rst_n, input is_link_up, headers_if if_headers_rx, input frame_type_t rx_type, input rx_done, headers_if if_headers_tx, output frame_type_t tx_type, output logic tx_start, input [31:0] data_recv, input [15:0] data_recv_len, input data_recv_valid, input data_recv_start, output logic rx_done_clear, input u32_t cur_ripaddr, input u16_t cur_rport, rx_ram_in_if.m if_rx_ram_in, tx_ram_out_if.m if_tx_ram_out, input [31:0] remote_port_local_port, input [31:0] local_ipaddr, input fifo_rdreq, output [31:0] fifo_q, input pkt_send_eop, output logic [13:0] tx_dword_count, output logic init_done
由于这个模块过于复杂,就不介绍了。
6.data_source
这个模块提供了与用户模块的接口
input rst_n, input init_done, input [7:0] wr_data, input wr_clk, input wr_en, output wr_full, output [7:0] rd_data, input rd_clk, input rd_en, output rd_empty, tx_ram_in_if.m if_tx_ram_in, rx_ram_out_if.s if_rx_ram_out )
其中wr开头和rd开头的都是对外提供的fifo接口, 分别用来写和读内部的发送FIFO和接收FIFO.
目前实现情况
目前udp协议可以基本全速运行,由于全速达到了100MB/s以上,如果处理速度慢,会有丢包的情况。
目前tcp协议只实现了最基本的功能,能够通信。窗口管理和慢启动,拥塞避免等特性还在完善中,速度只能达到200多M。
对这个工程的介绍就到这里了,希望对大家有用。
udp版本可以是开源的,但是商用需要license费。
tcp版本不开源,也是收费的。
需要的朋友可联系我qq:1517642772
相关文章推荐
- C#实现子窗体与父窗体通信方法实例总结
- C#基于UDP实现的P2P语音聊天工具
- C#基于UDP进行异步通信的方法
- TCP版backshell的VBS脚本代码
- java和c#使用hessian通信的方法
- 距离详解Linux下的UDP方式通讯
- win32下进程间通信(共享内存)实例分析
- WinForm实现跨进程通信的方法
- C#中使用UDP通信实例
- ASP.NET UserControl 通信的具体实现
- Linux网络编程之UDP Socket程序示例
- 服务器 UDP端口占用几千个的解决办法
- Android网络编程之UDP通信模型实例
- TCP Wrappers防火墙介绍与封锁IP地址的方法
- c语言多进程tcp服务器示例
- udp socket客户端和udp服务端程序示例分享
- 浅析iOS应用开发中线程间的通信与线程安全问题
- win2003连接限制TCP连接限制
- PHP多线程编程之管道通信实例分析