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 / 1psmodule top(input sysclk ,output eth_rst_n ,input rgmii_rx_clk ,input[3:0]rgmii_rxd ,inputrgmii_rx_dv ,output rgmii_tx_clk ,output[3:0]rgmii_txd ,outputrgmii_tx_en );wire rst_n;assign eth_rst_n = rst_n;clk_wiz_0 u0_clk_wiz_0 ( .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( outputgmii_rxc , outputgmii_rxdv , output [7:0] gmii_rxd , outputgmii_txc , input gmii_txen , input [7:0] gmii_txd , input rgmii_rxc , input rgmii_rx_ctrl , input [3:0] rgmii_rxd , outputrgmii_txc , outputrgmii_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 ); endendgenerateendmodule
仿真结果如下:
1.上下沿数据同时有效:
在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 OUTPUTODDR #( .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 ); endendgenerateendmodule
仿真结果如下:
在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可以正常抓取到输入的信号。