当前位置:   article > 正文

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

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核观测接口。

  1. `timescale 1ns / 1ps
  2. module top(
  3. input sysclk ,
  4. output eth_rst_n ,
  5. input rgmii_rx_clk ,
  6. input [3:0] rgmii_rxd ,
  7. input rgmii_rx_dv ,
  8. output rgmii_tx_clk ,
  9. output [3:0] rgmii_txd ,
  10. output rgmii_tx_en
  11. );
  12. wire clk_50M,rst_n;
  13. assign eth_rst_n = rst_n;
  14. clk_wiz_0 u0_clk_wiz_0
  15. (
  16. .clk_50M (clk_50M ), // output clk_200M
  17. .reset (1'd0 ), // input reset
  18. .locked (rst_n ),
  19. .clk_in1 (sysclk )
  20. );
  21. wire gmii_rx_clk ;
  22. wire gmii_rx_dv ;
  23. wire [7:0] gmii_rxd ;
  24. wire gmii_tx_clk ;
  25. wire gmii_tx_en ;
  26. wire [7:0] gmii_txd ;
  27. rgmii_to_gmii u1_rgmii_to_gmii(
  28. .gmii_rxc (gmii_rx_clk ),
  29. .gmii_rxdv (gmii_rx_dv ),
  30. .gmii_rxd (gmii_rxd ),
  31. .gmii_txc (gmii_tx_clk ),
  32. .gmii_txen (gmii_tx_en ),
  33. .gmii_txd (gmii_txd ),
  34. .rgmii_rxc (rgmii_rx_clk ),
  35. .rgmii_rx_ctrl (rgmii_rx_dv ),
  36. .rgmii_rxd (rgmii_rxd ),
  37. .rgmii_txc (rgmii_tx_clk ),
  38. .rgmii_tx_ctrl (rgmii_tx_en ),
  39. .rgmii_txd (rgmii_txd )
  40. );
  41. ila_16 ila_u (
  42. .clk(gmii_rx_clk), // input wire clk
  43. .probe0({gmii_rx_dv,gmii_rxd}) // input wire [15:0] probe0
  44. );
  45. endmodule

3.rgmii_to_gmii模块

例化rgmii接口的收发模块

  1. module rgmii_to_gmii(
  2. output gmii_rxc ,
  3. output gmii_rxdv ,
  4. output [7:0] gmii_rxd ,
  5. output gmii_txc ,
  6. input gmii_txen ,
  7. input [7:0] gmii_txd ,
  8. input rgmii_rxc ,
  9. input rgmii_rx_ctrl ,
  10. input [3:0] rgmii_rxd ,
  11. output rgmii_txc ,
  12. output rgmii_tx_ctrl ,
  13. output [3:0] rgmii_txd
  14. );
  15. assign gmii_txc = gmii_rxc;
  16. rgmii_rxd rgmii_rxd_inst(
  17. .rgmii_rxc (rgmii_rxc ),
  18. .rgmii_rx_ctrl (rgmii_rx_ctrl ),
  19. .rgmii_rxd (rgmii_rxd ),
  20. .gmii_rxc (gmii_rxc ),
  21. .gmii_rxdv (gmii_rxdv ),
  22. .gmii_rxd (gmii_rxd )
  23. );
  24. rgmii_txd rgmii_txd_inst(
  25. .gmii_txc (gmii_txc ),
  26. .gmii_txen (gmii_txen ),
  27. .gmii_txd (gmii_txd ),
  28. .rgmii_txc (rgmii_txc ),
  29. .rgmii_tx_ctrl (rgmii_tx_ctrl ),
  30. .rgmii_txd (rgmii_txd )
  31. );
  32. endmodule

4.rgmii_rxd模块

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

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

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

  1. module rgmii_rxd(
  2. input rgmii_rxc ,
  3. input rgmii_rx_ctrl ,
  4. input [3:0] rgmii_rxd ,
  5. output gmii_rxc ,
  6. output gmii_rxdv ,
  7. output [7:0] gmii_rxd
  8. );
  9. wire rgmii_rxc_bufio; //全局时钟IO缓存
  10. wire [1:0] gmii_rxdv_t; //上下沿有效信号
  11. BUFG BUFG_inst (
  12. .I (rgmii_rxc), // 1-bit input: Clock input
  13. .O (gmii_rxc) // 1-bit output: Clock output
  14. );
  15. BUFIO BUFIO_inst (
  16. .I (rgmii_rxc), // 1-bit input: Clock input
  17. .O (rgmii_rxc_bufio) // 1-bit output: Clock output
  18. );
  19. IDDR #(
  20. .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE"
  21. // or "SAME_EDGE_PIPELINED"
  22. .INIT_Q1 (1'b0), // Initial value of Q1: 1'b0 or 1'b1
  23. .INIT_Q2 (1'b0), // Initial value of Q2: 1'b0 or 1'b1
  24. .SRTYPE ("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
  25. ) IDDR_inst (
  26. .Q1 (gmii_rxdv_t[0]), // 1-bit output for positive edge of clock
  27. .Q2 (gmii_rxdv_t[1]), // 1-bit output for negative edge of clock
  28. .C (rgmii_rxc_bufio), // 1-bit clock input
  29. .CE (1'b1), // 1-bit clock enable input
  30. .D (rgmii_rx_ctrl), // 1-bit DDR data input
  31. .R (1'b0), // 1-bit reset
  32. .S (1'b0) // 1-bit set
  33. );
  34. assign gmii_rxdv = gmii_rxdv_t[0]&gmii_rxdv_t[1];
  35. genvar i;
  36. generate for (i=0; i<4; i=i+1)
  37. begin : rxdata_bus
  38. IDDR #(
  39. .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),// "OPPOSITE_EDGE", "SAME_EDGE"
  40. // or "SAME_EDGE_PIPELINED"
  41. .INIT_Q1 (1'b0), // Initial value of Q1: 1'b0 or 1'b1
  42. .INIT_Q2 (1'b0), // Initial value of Q2: 1'b0 or 1'b1
  43. .SRTYPE ("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
  44. ) IDDR_inst (
  45. .Q1 (gmii_rxd[i]), // 1-bit output for positive edge of clock
  46. .Q2 (gmii_rxd[4+i]), // 1-bit output for negative edge of clock
  47. .C (rgmii_rxc_bufio), // 1-bit clock input rgmii_rxc_buf
  48. .CE (1'b1), // 1-bit clock enable input
  49. .D (rgmii_rxd[i]), // 1-bit DDR data input
  50. .R (1'b0), // 1-bit reset
  51. .S (1'b0) // 1-bit set
  52. );
  53. end
  54. endgenerate
  55. 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原语实现。

  1. module rgmii_txd(
  2. input gmii_txc ,
  3. input gmii_txen ,
  4. input [7:0] gmii_txd ,
  5. output rgmii_txc ,
  6. output rgmii_tx_ctrl ,
  7. output [3:0] rgmii_txd
  8. );
  9. assign rgmii_txc = gmii_txc;
  10. // TX CTRL DDR OUTPUT
  11. ODDR #(
  12. .DDR_CLK_EDGE ("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
  13. .INIT (1'b0), // Initial value of Q: 1'b0 or 1'b1
  14. .SRTYPE ("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
  15. ) ODDR_inst (
  16. .Q (rgmii_tx_ctrl), // 1-bit DDR output
  17. .C (gmii_txc), // 1-bit clock input
  18. .CE (1'b1), // 1-bit clock enable input
  19. .D1 (gmii_txen), // 1-bit data input (positive edge)
  20. .D2 (gmii_txen), // 1-bit data input (negative edge)
  21. .R (1'b0), // 1-bit reset
  22. .S (1'b0) // 1-bit set
  23. );
  24. genvar i;
  25. generate for (i=0; i<4; i=i+1) //TXD DDR OUTPUT
  26. begin : txd_ddr
  27. ODDR #(
  28. .DDR_CLK_EDGE ("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
  29. .INIT (1'b0), // Initial value of Q: 1'b0 or 1'b1
  30. .SRTYPE ("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
  31. ) ODDR_inst (
  32. .Q (rgmii_txd[i]), // 1-bit DDR output
  33. .C (gmii_txc), // 1-bit clock input
  34. .CE (1'b1), // 1-bit clock enable input
  35. .D1 (gmii_txd[i]), // 1-bit data input (positive edge)
  36. .D2 (gmii_txd[4+i]), // 1-bit data input (negative edge)
  37. .R (1'b0), // 1-bit reset
  38. .S (1'b0) // 1-bit set
  39. );
  40. end
  41. endgenerate
  42. 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可以正常抓取到输入的信号。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/866675
推荐阅读
相关标签
  

闽ICP备14008679号