FPGA实现千兆网UDP协议(一):RGMII接口(附源码)

目录

一、RGMII接口介绍

二、RGMII接口定义

三、RGMII接口时序

1.FPGA接收数据时序

2.FPGA发送数据时序

四、RGMII模块设计

1.模块框图

2.顶层模块

3.rgmii_to_gmii模块

4.rgmii_rxd模块

5.rgmii_txd模块

6.运行结果


一、RGMII接口介绍

RGMII接口是FPGA芯片与PHY芯片进行通信的接口,全称Reduced Gigabit Media Independent Interface(吉比特介质独立接口),支持10 Mbps,100 Mbps和1000 Mbps的PHY层连接速度。


二、RGMII接口定义

序号

引脚

方向

描述

1

TXC

MAC  →  PHY

发送时钟

2

TX_CTL

MAC  →  PHY

发送使能

3

TXD

MAC  →  PHY

发送数据

4

RXC

PHY  →  MAC

接收时钟

5

RX_CTL

PHY  →  MAC

接收使能

6

RXD

PHY  →  MAC

接收数据

7

MDC

MAC  →  PHY

PHY配置时钟

8

MDIO

MAC ←→ PHY

PHY配置读写

在1000 Mbps模式下,TXC和RXC为125 MHz,时钟的上升沿和下降沿同时传输数据,每次传输4bit数据。所以总速率为:125M*2*4bit / 1s = 1000Mbps。

本次实验FPGA开发板配套PHY芯片引脚定义如下:除去数据收发引脚,还有ETH_INT及PHYRSTB引脚, 用于初始化和复位,没有特殊需求一直给高电平芯片就能正常运行。


三、RGMII接口时序

1.FPGA接收数据时序

PHY芯片发送数据时,在时钟的上升沿发送字节的低4位,在下降沿发送字节的高4位。

当RX_CTL上升沿和下降沿均为1时,表示数据有效,无何何错误。

当RX_CTL上升沿为1,下降沿为0时,表示当前时钟周期的数据错误。

开发板卡在设计时通常会通过在PCB走线、在控制器端或在PHY芯片内部添加时钟偏移,让其工作在延时模式。

简言之就是PHY芯片发送的数据是在时钟的上升沿以及下降沿变化的,如下图。

然后通过时钟偏移,偏移90度,让FPGA收到的时钟沿和数据的中心对齐,如下图。

如果不做任何处理,FPGA是无法在时钟沿上正确的采集到每个数据。

本次实验所采用芯片为RTL8211E,如图2,根据芯片手册,如下表,16及32引脚均通过上拉电阻拉高,PHY芯片已经工作于延时模式。

PIN

PIN_NAME

DESCRIPTION

16

TXDLY

1: Add 2ns delay to TXC for TXD latching

32

RXDLY

1: Add 2ns delay to RXC for RXD latching

2.FPGA发送数据时序

FPGA芯片发送数据时,在时钟的上升沿发送字节的低4位,在下降沿发送字节的高4位。

根据PHY芯片是否工作在延时模式,FPGA芯片对发送时钟进行调整。

如果PHY芯片是在延时模式,则发送时钟不做处理。

如果未在延时模式,则发送时钟偏移90度相位。

本次实验RTL8211芯片工作于延时模式,发送时钟不做处理。


四、RGMII模块设计

1.模块框图

主模块:rgmii_to_gmii模块

包含2个子模块:rgmii_rxd 模块, rgmii_txd 模块

2.顶层模块

顶层按照原理图引入相关接口,MDC以及MDIO接口此处对PHY芯片无配置需求,暂不引入,引入clk_wiz IP核输出复位接口,引入ila IP核观测接口。

`timescale 1ns / 1ps

module top(
input               sysclk         ,
output              eth_rst_n      ,
input               rgmii_rx_clk   ,
input	[3:0]		rgmii_rxd      ,
input				rgmii_rx_dv    ,
output              rgmii_tx_clk   ,
output	[3:0]		rgmii_txd      ,
output				rgmii_tx_en    
    );

wire  clk_50M,rst_n;
assign  eth_rst_n = rst_n;
clk_wiz_0 u0_clk_wiz_0
   (
    .clk_50M    (clk_50M    ),      // output clk_200M
    .reset      (1'd0       ),      // input reset
    .locked     (rst_n      ),      
    .clk_in1    (sysclk     )      
); 

wire        gmii_rx_clk ;
wire        gmii_rx_dv  ;
wire [7:0]  gmii_rxd    ;
wire        gmii_tx_clk ; 
wire        gmii_tx_en  ;  
wire [7:0]  gmii_txd    ;
rgmii_to_gmii  u1_rgmii_to_gmii(
.gmii_rxc       (gmii_rx_clk    ),
.gmii_rxdv      (gmii_rx_dv     ),
.gmii_rxd       (gmii_rxd       ),
.gmii_txc       (gmii_tx_clk    ),
.gmii_txen      (gmii_tx_en     ),
.gmii_txd       (gmii_txd       ),
.rgmii_rxc      (rgmii_rx_clk   ),
.rgmii_rx_ctrl  (rgmii_rx_dv    ),
.rgmii_rxd      (rgmii_rxd      ),
.rgmii_txc      (rgmii_tx_clk   ),
.rgmii_tx_ctrl  (rgmii_tx_en    ),
.rgmii_txd      (rgmii_txd      )
    );

ila_16 ila_u (
	.clk(gmii_rx_clk), // input wire clk
	.probe0({gmii_rx_dv,gmii_rxd}) // input wire [15:0] probe0
);
endmodule

3.rgmii_to_gmii模块

例化rgmii接口的收发模块

module rgmii_to_gmii(   
    output                      gmii_rxc        ,          
    output                      gmii_rxdv       ,      
    output          [7:0]       gmii_rxd        ,     
    output                      gmii_txc        ,           
    input                       gmii_txen       ,         
    input           [7:0]       gmii_txd        ,         
    input                       rgmii_rxc       ,        
    input                       rgmii_rx_ctrl   ,       
    input           [3:0]       rgmii_rxd       ,        
    output                      rgmii_txc       ,        
    output                      rgmii_tx_ctrl   ,       
    output          [3:0]       rgmii_txd            
    );

assign gmii_txc = gmii_rxc;
 
rgmii_rxd rgmii_rxd_inst(
    .rgmii_rxc      (rgmii_rxc          ),
    .rgmii_rx_ctrl  (rgmii_rx_ctrl      ),
    .rgmii_rxd      (rgmii_rxd          ),
    .gmii_rxc       (gmii_rxc           ),
    .gmii_rxdv      (gmii_rxdv          ),
    .gmii_rxd       (gmii_rxd           )

    );

rgmii_txd rgmii_txd_inst(
    .gmii_txc       (gmii_txc       ),
    .gmii_txen      (gmii_txen      ),
    .gmii_txd       (gmii_txd       ),
    .rgmii_txc      (rgmii_txc      ),
    .rgmii_tx_ctrl  (rgmii_tx_ctrl  ),
    .rgmii_txd      (rgmii_txd      )
    );

endmodule

4.rgmii_rxd模块

通过IDDR原语,对PHY芯片输入的双沿信号处理成单沿信号,包含使能信号以及4bit数据信号。

使能信号处理方式为:时钟的上下沿使能信号同时为高电平时,在下一个时钟输出高电平,只要有一个沿为低电平,最终就不会输出高电平。

数据信号处理方式为:时钟的上沿数据作为低4bit,下沿数据作为高4bit,在下一个时钟组合输出一个8bit数据。

module rgmii_rxd(
    input              rgmii_rxc        ,  
    input              rgmii_rx_ctrl    ,  
    input       [3:0]  rgmii_rxd        ,  
    output             gmii_rxc         ,  
    output             gmii_rxdv        ,  
    output      [7:0]  gmii_rxd            
    );

 
wire         rgmii_rxc_bufio;       //全局时钟IO缓存
wire  [1:0]  gmii_rxdv_t;           //上下沿有效信号 

BUFG BUFG_inst (
  .I            (rgmii_rxc),     // 1-bit input: Clock input
  .O            (gmii_rxc)       // 1-bit output: Clock output
);

BUFIO BUFIO_inst (
  .I            (rgmii_rxc),      // 1-bit input: Clock input
  .O            (rgmii_rxc_bufio) // 1-bit output: Clock output
);

IDDR #(
    .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE" 
                                        //    or "SAME_EDGE_PIPELINED" 
    .INIT_Q1  (1'b0),                   // Initial value of Q1: 1'b0 or 1'b1
    .INIT_Q2  (1'b0),                   // Initial value of Q2: 1'b0 or 1'b1
    .SRTYPE   ("SYNC")                  // Set/Reset type: "SYNC" or "ASYNC" 
) IDDR_inst (
    .Q1       (gmii_rxdv_t[0]),         // 1-bit output for positive edge of clock
    .Q2       (gmii_rxdv_t[1]),         // 1-bit output for negative edge of clock
    .C        (rgmii_rxc_bufio),        // 1-bit clock input
    .CE       (1'b1),                   // 1-bit clock enable input
    .D        (rgmii_rx_ctrl),          // 1-bit DDR data input
    .R        (1'b0),                   // 1-bit reset
    .S        (1'b0)                    // 1-bit set
);
assign gmii_rxdv = gmii_rxdv_t[0]&gmii_rxdv_t[1];

genvar i;
generate for (i=0; i<4; i=i+1)
    begin : rxdata_bus   
        IDDR #(
            .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE" 
                                                //    or "SAME_EDGE_PIPELINED" 
            .INIT_Q1  (1'b0),                   // Initial value of Q1: 1'b0 or 1'b1
            .INIT_Q2  (1'b0),                   // Initial value of Q2: 1'b0 or 1'b1
            .SRTYPE   ("SYNC")                  // Set/Reset type: "SYNC" or "ASYNC" 
        ) IDDR_inst (
            .Q1       (gmii_rxd[i]),            // 1-bit output for positive edge of clock
            .Q2       (gmii_rxd[4+i]),          // 1-bit output for negative edge of clock
            .C        (rgmii_rxc_bufio),        // 1-bit clock input rgmii_rxc_buf
            .CE       (1'b1),                   // 1-bit clock enable input
            .D        (rgmii_rxd[i]),           // 1-bit DDR data input
            .R        (1'b0),                   // 1-bit reset
            .S        (1'b0)                    // 1-bit set
        );
    end
endgenerate

endmodule

仿真结果如下:

1.上下沿数据同时有效:

信号名称        信号定义
rgmii_rxcPHY芯片输入的时钟
rgmii_rx_ctrl  PHY芯片输入的使能信号
rgmii_rxd   PHY芯片输入的4bit数据
gmii_rxdv   模块输出的使能信号
gmii_rxdv模块输出的8bit数据

在112ns时上升沿采样到低4位4’b0001,在116ns时下降沿采样到高4位0010,在120ns时将前两次采样的结果组合成8’b00100001输出。

2.上下沿数据非同时有效:

在112ns时上升沿采样到低4位4’b0001,在116ns时使能信号消失,下降沿未采样高4位数据,在120ns时将不会有数据输出。

5.rgmii_txd模块

    将输入的8bit信号以及使能信号处理成双沿信号,通过ODDR原语实现。

module rgmii_txd(
    input              gmii_txc         ,     
    input              gmii_txen        ,   
    input       [7:0]  gmii_txd         ,  
    output             rgmii_txc        ,  
    output             rgmii_tx_ctrl    , 
    output      [3:0]  rgmii_txd      
    );
assign rgmii_txc = gmii_txc;

// TX CTRL DDR OUTPUT
ODDR #(
    .DDR_CLK_EDGE  ("SAME_EDGE"),  // "OPPOSITE_EDGE" or "SAME_EDGE" 
    .INIT          (1'b0),         // Initial value of Q: 1'b0 or 1'b1
    .SRTYPE        ("SYNC")        // Set/Reset type: "SYNC" or "ASYNC" 
) ODDR_inst (
    .Q             (rgmii_tx_ctrl), // 1-bit DDR output
    .C             (gmii_txc),      // 1-bit clock input
    .CE            (1'b1),          // 1-bit clock enable input
    .D1            (gmii_txen),     // 1-bit data input (positive edge)
    .D2            (gmii_txen),     // 1-bit data input (negative edge)
    .R             (1'b0),          // 1-bit reset
    .S             (1'b0)           // 1-bit set
); 
genvar i;
generate for (i=0; i<4; i=i+1)  //TXD DDR OUTPUT
    begin : txd_ddr
        ODDR #(
            .DDR_CLK_EDGE  ("SAME_EDGE"),   // "OPPOSITE_EDGE" or "SAME_EDGE" 
            .INIT          (1'b0),          // Initial value of Q: 1'b0 or 1'b1
            .SRTYPE        ("SYNC")         // Set/Reset type: "SYNC" or "ASYNC" 
        ) ODDR_inst (
            .Q             (rgmii_txd[i]),  // 1-bit DDR output
            .C             (gmii_txc),      // 1-bit clock input
            .CE            (1'b1),          // 1-bit clock enable input
            .D1            (gmii_txd[i]),   // 1-bit data input (positive edge)
            .D2            (gmii_txd[4+i]), // 1-bit data input (negative edge)
            .R             (1'b0),          // 1-bit reset
            .S             (1'b0)           // 1-bit set
        );        
    end
endgenerate

endmodule

仿真结果如下:

信号名称信号定义
gmii_txc 模块输入的时钟
gmii_tx_en模块输入的使能信号
gmii_txd模块输入的8bit数据
rgmii_tx_ctrl向PHY芯片输出的使能信号
rgmii_txd向PHY芯片输出的4bit数据

在112ns时上升沿采样到数据8’b00100001,在120ns时上升沿输出低4位4’b0001,在124ns时下降沿输出高4位4’b0010。

6.运行结果

1.将开发板与PC通过网线连接,烧录好bit文件。

2.进入控制面板,查看当前网卡是否工作在千兆模式。

3.配置网卡地址为192.168.10.49 ,掩码为255.255.255.0。

也可配置为其他地址,但后续为板卡分配地址时一定要和PC的网卡地址在同一网段。

4.键入win+R,输入cmd打开PC控制台。

5.输入ping 192.168.10.XXX 命令,PC网卡主动发出数据包。

6.PHY芯片正常收到数据后将数据传给FPGA,FPGA可以正常抓取到输入的信号。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值