xilinx c语言u16,EETOP 赛灵思(Xilinx) 社区

基于FPGA的千兆以太网UDP 硬件协议栈

发布者:jackzhang

时间:2016-03-29 13:37:25

原文:http://bbs.eetop.cn/thread-593390-1-2.html

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

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

下面是工程的示意图.

1602011428316be4d5112dfa51.jpg

这个工程由几部分组成, 外部使用了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,

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协议可以基本全速运行,但是有丢包的情况,需要有个确认机制。

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值