基于FPGA 以太网gmii_to_rgmii模块编写 附源码

这篇具有很好参考价值的文章主要介绍了基于FPGA 以太网gmii_to_rgmii模块编写 附源码。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

笔者使用的开发板是米联客zynq UitraScale+ xczu4ev-sfvc784-2-i开发板进行测试

由于米联客协议族源码不开源,自己写了一个简易的以太网接口转换模块只支持1000M速率。

一、接口框图:(引用原子哥)

基于FPGA 以太网gmii_to_rgmii模块编写 附源码

二、RGMII接口时序简介:

(1)接收时序(PHY>FPGA)

RXC 的上下边沿与 RXD 和 RX_CTL 信号对齐,相位相同。(非延时模式)

基于FPGA 以太网gmii_to_rgmii模块编写 附源码

RXC 的上下边沿与 RXD 和 RX_CTL 信号的中间位置对齐,相位相差90度(延时模式)

RXC 的时钟周期为 8ns,单个高电平或者低电平为 4ns, RXC 相对于 RXD 和 RX_CTL 延时约 2ns。

基于FPGA 以太网gmii_to_rgmii模块编写 附源码

(2)发送时序(FPGA>PHY)

TXC 的上下边沿与 TXD 和 TX_CTL 信号对齐,相位相同。 (非延时模式)

基于FPGA 以太网gmii_to_rgmii模块编写 附源码

RGMII 发送端口在 TXC 时钟的上升沿传输 TXD 的低 4 位和 TX_CTL 的使能信号;

下降沿传输 TXD 的高 4 位和 TX_CTL 的错误信号(实际上是使能信号和错误信号的异或值); RGMII 接收端口在RXC 时钟的上升沿传输 RXD 的低 4 位和 RX_CTL 的使能信号;

下降沿传输RXD 的高 4 位和RX_CTL 的错误信号(实际上是使能信号和错误信号的异或值)。(延时模式)

基于FPGA 以太网gmii_to_rgmii模块编写 附源码
注意:笔者芯片接收时序为延时模式,发送时序为正常模式,具体模式需参考相应原理图引脚上下拉判断,也可通过MDIO配置。

三、原语使用

UitraScale+系列的开发板原语使用和7系列大不相同,需要了解IDDRE1、ODDRE1、BUFG、BUFIO、IDELAYE3 、 ODELAYE3。在本次测试中并未使用IDELAYE3 、 ODELAYE3不做研究,原因是其phy芯片rxd端采用延时模式txd采用非延时模式(输出我们采用pll的方法相位偏移90度)。

//全局缓冲, BUFG 的输出到达 FPGA 内部的 IOB、 CLB、块 RAM 的时钟延迟和抖动最小。
BUFG BUFG_inst (
  .I            (rgmii_rxc),     // 1-bit input: Clock input
  .O            (rgmii_clk_buf) // 1-bit output: Clock output
);
//BUFIO 是 IO 时钟网络,其独立于全局时钟资源,适合采集源同步数据。它只能驱动 IO Block 里面的逻辑,不能驱动  CLB 里面的 LUT, REG 等逻辑。
BUFIO BUFIO_inst (
  .I            (rgmii_rxc),      // 1-bit input: Clock input
  .O            (rgmii_rxc_bufio) // 1-bit output: Clock output
);
//将输入的上下边沿 DDR 信号,转换成两位单边沿 SDR 信号。 
IDDRE1 #(
    .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)模式选择一般选择SAME_EDGE_PIPELINED模式
    .IS_CB_INVERTED(1'b1),          // Optional inversion for CB,高速时钟CB反向使能
    .IS_C_INVERTED(1'b0)            // Optional inversion for C,高速时钟C反向不使能
 )
 IDDRE1_inst (
    .Q1(w_gmii_rx_dv), // 1-bit output: Registered parallel output 1输出低4位
    .Q2(w_rgmii_rx_ctl), // 1-bit output: Registered parallel output 2输出高4位
    .C(rgmii_rxc_bufio),   // 1-bit input: High-speed clock高速时钟输入
    .CB(rgmii_rxc_bufio), // 1-bit input: Inversion of High-speed clock C高速时钟c的反转
与这个IS_CB_INVERTED参数互斥
    .D(rgmii_rx_ctl),   // 1-bit input: Serial Data Input8位数据输入
    .R(1'b0)    // 1-bit input: Active-High Async Reset置位/复位信号,高有效
 );
//把两路单端的数据合并到一路上输出,上下沿同时输出数据,上升沿输出 a路,下降沿输出 b 路
ODDRE1 #(
    .IS_C_INVERTED     (1'b0                   ),  // Optional inversion for C c的反转
    .IS_D1_INVERTED    (1'b0                   ),  // Unsupported, do not use无用默认
    .IS_D2_INVERTED    (1'b0                   ),  // Unsupported, do not use无用默认
    .SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,设备版本选择
    .SRVAL             (1'b0                   )   // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)初始化ODDRE1触发器到指定值(1'bo, 1'b1)
    )
    u_rgmii_tx_ctl 
    (
         .Q                 (rgmii_tx_ctl           ),   // 1-bit output: Data output to IOB 8位数据输出
         .C                 (gmii_tx_clk            ),   // 1-bit input: High-speed clock input高速时钟输入
         .D1                (gmii_tx_en             ), // 1-bit input: Parallel data input 1输入数据低4位
         .D2                (gmii_tx_er             ), // 1-bit input: Parallel data input 2输入数据高4位
         .SR                (0                      )    // 1-bit input: Active High Async Reset置位/复位信号,高有效
);

四、源码

代码写法有很多笔者也参考了很多厂商dmo有误请在评论区指正

module gmii_rgmii(
    input     wire                    rgmii_rxc        ,//输入时钟
    input     wire    [3:0]           rgmii_rxd        ,//输入数据
    input     wire                    rgmii_rx_ctl     ,//输入控制

    output    wire    [3:0]           rgmii_txd        ,//输出数据
    output    wire                    rgmii_tx_ctl     ,//输出控制
    output    wire                    rgmii_txc        ,//发送时钟

    output    wire                    gmii_rx_clk      ,//输出接收时钟
    output    wire     [7:0]          gmii_rxd         ,//输入8位数据
    output    wire                    gmii_rx_dv       ,//输出数据有效

    input     wire    [7:0]           gmii_txd         ,//输入8位数据
    input     wire                    gmii_tx_en       ,//输入发送使能高有效
    input     wire                    gmii_tx_er       ,//输入数据是否有误高有效
    output    wire                    gmii_tx_clk       //输出发送时钟
 );
 
     wire                     w_gmii_rx_dv   ;
     wire                     w_rgmii_rx_ctl ;
     wire                     rgmii_rxc_bufio;
     wire                     rgmii_clk_buf  ;

 /*              Rgmii rx                  */
 

BUFG BUFG_inst (
  .I            (rgmii_rxc),     // 1-bit input: Clock input
  .O            (rgmii_clk_buf) // 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
);
assign gmii_rx_clk = rgmii_clk_buf;
assign gmii_tx_clk = rgmii_clk_buf;
assign gmii_rx_dv  = (w_gmii_rx_dv & w_rgmii_rx_ctl);

IDDRE1 #(
    .DDR_CLK_EDGE("SAME_EDGE_PIPELINED"), // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
    .IS_CB_INVERTED(1'b1),          // Optional inversion for CB
    .IS_C_INVERTED(1'b0)            // Optional inversion for C
 )
 IDDRE1_inst (
    .Q1(w_gmii_rx_dv), // 1-bit output: Registered parallel output 1
    .Q2(w_rgmii_rx_ctl), // 1-bit output: Registered parallel output 2
    .C(rgmii_rxc_bufio),   // 1-bit input: High-speed clock
    .CB(rgmii_rxc_bufio), // 1-bit input: Inversion of High-speed clock C
    .D(rgmii_rx_ctl),   // 1-bit input: Serial Data Input
    .R(1'b0)    // 1-bit input: Active-High Async Reset
 );

genvar i;
generate
    for (i = 0; i < 4; i = i + 1) 
    begin : rxdata_bus
        IDDRE1 #(
            .DDR_CLK_EDGE     ("SAME_EDGE_PIPELINED"   ),  // IDDRE1 mode (OPPOSITE_EDGE, SAME_EDGE, SAME_EDGE_PIPELINED)
            .IS_CB_INVERTED   (1'b1                    ),  // Optional inversion for CB
            .IS_C_INVERTED    (1'b0                    )   // Optional inversion for C
        )
        u_rgmii_rxd
        (
            .Q1               (gmii_rxd[i]             ),  // 1-bit output: Registered parallel output 1
            .Q2               (gmii_rxd[i+4]           ),  // 1-bit output: Registered parallel output 2
            .C                (rgmii_rxc_bufio         ),  // 1-bit input: High-speed clock
            .CB               (rgmii_rxc_bufio         ),  // 1-bit input: Inversion of High-speed clock C
            .D                (rgmii_rxd[i]            ),  // 1-bit input: Serial Data Input
            .R                (0                       )   // 1-bit input: Active High Async Reset
        );
    end
 endgenerate
   
 /*                         Rgmii tx                        */
 
assign rgmii_txc=gmii_tx_clk;

ODDRE1 #(
    .IS_C_INVERTED     (1'b0                   ),  // Optional inversion for C
    .IS_D1_INVERTED    (1'b0                   ),  // Unsupported, do not use
    .IS_D2_INVERTED    (1'b0                   ),  // Unsupported, do not use
    .SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,
    .SRVAL             (1'b0                   )   // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
    )
    u_rgmii_tx_ctl 
    (
         .Q                 (rgmii_tx_ctl           ),   // 1-bit output: Data output to IOB
         .C                 (gmii_tx_clk            ),   // 1-bit input: High-speed clock input
         .D1                (gmii_tx_en             ),   // 1-bit input: Parallel data input 1
         .D2                (gmii_tx_er             ),   // 1-bit input: Parallel data input 2
         .SR                (0                      )    // 1-bit input: Active High Async Reset
);
    
genvar j;
generate
    for (j = 0; j < 4; j = j + 1)
     begin: txdata_bus
        ODDRE1 #(
            .IS_C_INVERTED     (1'b0                   ),  // Optional inversion for C
            .IS_D1_INVERTED    (1'b0                   ),  // Unsupported, do not use
            .IS_D2_INVERTED    (1'b0                   ),  // Unsupported, do not use
            .SIM_DEVICE("ULTRASCALE"), // Set the device version (ULTRASCALE, ULTRASCALE_PLUS, ULTRASCALE_PLUS_ES1,
            .SRVAL             (1'b0                   )   // Initializes the ODDRE1 Flip-Flops to the specified value (1'b0, 1'b1)
        )
        u_rgmii_txd
        (
            .Q                 (rgmii_txd[j]           ),  // 1-bit output: Data output to IOB
            .C                 (gmii_tx_clk            ),  // 1-bit input: High-speed clock input
            .D1                (gmii_txd[j]            ),  // 1-bit input: Parallel data input 1
            .D2                (gmii_txd[4+j]          ),  // 1-bit input: Parallel data input 2
            .SR                (0                      )   // 1-bit input: Active High Async Reset
        );
    end
endgenerate
   
endmodule

pll资源配置:

基于FPGA 以太网gmii_to_rgmii模块编写 附源码
基于FPGA 以太网gmii_to_rgmii模块编写 附源码

顶层例化使用

//MMCM/PLL偏移90度
clk_wiz_0 u_clk_wiz(
  // Clock out ports
  .clk_out1   (clk_125m_deg),       // output clk_out1
  // Status and control signals
  //.reset      (~sys_rst_n  ),       // input reset
  .locked     (locked      ),       // output locked
 // Clock in ports
  .clk_in1    (rgmii_txc   )        // input clk_in1
  );  

五、仿真

有点乱码不影响查看

`timescale 1ns / 1ps
module gmii_rgmii_tb();
    reg                         rgmii_rxc        ;//閹恒儲鏁归弮鍫曟�?
    reg                         clk             ;//婢跺秳锟??
    wire       [3:0]            rgmii_txd        ;//閸欐埊锟???閿熻姤鏆熼敓??
    wire                        rgmii_tx_ctl     ;//閺佺増宓�?幒褍�???
    wire                        rgmii_txc        ;//閸欐埊锟???閿熻姤妞傞敓??
    reg         [3:0]           rgmii_rxd        ;//閹恒儲鏁归弫鐗堝�?
    reg                         rgmii_rx_ctl     ;//閹恒儲鏁归弫鐗堝祦閹貉冨�?
    wire                        gmii_rx_clk      ;//閺佺増宓佺憴锝嗭�??锟介幒銉︽暪閺冨爼锟??
    reg         [7:0]           gmii_txd         ;//鏉堟挸鍙嗛弫鐗堝�?
    reg                         gmii_tx_en       ;//閺佺増宓佹担鑳�?
    reg                         gmii_tx_er       ;//閺佺増宓�?柨娆掝嚖
    wire                        gmii_tx_clk      ;//閺佺増宓�?崣鎴嫹?閿熻姤妞傞敓??
    wire         [7:0]          gmii_rxd         ;//閹恒儲鏁归弫鐗堝�?
    wire                        gmii_rx_dv       ;//閹恒儲鏁归弫鐗堝祦閺堝�???
 
 initial begin 
     clk=0;
     rgmii_rxc=0;rgmii_rxd=4'd1;gmii_txd=8'b1;
 end
 
 always #8  rgmii_rxc=!rgmii_rxc;
 always #4  clk=!clk;
 initial begin
     rgmii_rx_ctl=1;gmii_tx_en=1'b1;gmii_tx_er=1'b1;
     #100;
 end
 
 always@(posedge rgmii_rxc)begin
     #1
     if(gmii_txd==15)gmii_txd=0;
     else
     gmii_txd=gmii_txd+1'b1;
 end
 
 always@(posedge clk )begin
     #1
     if(rgmii_rxd==40)rgmii_rxd=0;
     else
     rgmii_rxd=rgmii_rxd+1'b1;
 end
 
 gmii_rgmii gmii_rgmii(
    /*input     wire                   */. rgmii_rxc       (rgmii_rxc) ,//閹恒儲鏁归弮鍫曟�?
    /*output    wire    [3:0]          */. rgmii_txd       (rgmii_txd) ,//閸欐埊锟???閿熻姤鏆熼敓??
    /*output    wire                   */. rgmii_tx_ctl    (rgmii_tx_ctl) ,//閺佺増宓�?幒褍�???
    /*output    wire                   */. rgmii_txc       (rgmii_txc) ,//閸欐埊锟???閿熻姤妞傞敓??
    /*input     wire    [3:0]          */. rgmii_rxd       (rgmii_rxd) ,//閹恒儲鏁归弫鐗堝�?
    /*input     wire                   */. rgmii_rx_ctl    (rgmii_rx_ctl) ,//閹恒儲鏁归弫鐗堝祦閹貉冨�?
 
    /*output    wire                   */. gmii_rx_clk     (gmii_rx_clk) ,//閺佺増宓佺憴锝嗭�??锟介幒銉︽暪閺冨爼锟??
    /*input     wire    [7:0]          */. gmii_txd        (gmii_txd) ,//鏉堟挸鍙嗛弫鐗堝�?
    /*input     wire                   */. gmii_tx_en      (gmii_tx_en) ,//閺佺増宓佹担鑳�?
    /*input     wire                   */. gmii_tx_er      (gmii_tx_er) ,//閺佺増宓�?柨娆掝嚖
    /*output    wire                   */. gmii_tx_clk     (gmii_tx_clk) ,//閺佺増宓�?崣鎴嫹?閿熻姤妞傞敓??
    /*output    reg     [7:0]          */. gmii_rxd        (gmii_rxd) ,//閹恒儲鏁归弫鐗堝�?
    /*output    reg                    */. gmii_rx_dv      (gmii_rx_dv)  //閹恒儲鏁归弫鐗堝祦閺堝�???
 );
 
 endmodule
 
基于FPGA 以太网gmii_to_rgmii模块编写 附源码

注意:发送时钟并未体现数据中间采样是因为时钟输出采用pll使相位偏移90度在顶层实现

对了由于是高速接口需添加时序约束。时钟是由PHY芯片产生的125Mhz时钟需要添加引脚输入的主时钟约束到.xdc文件中(注意放在引脚约束前)如下:文章来源地址https://www.toymoban.com/news/detail-461206.html

create_clock -period 8.000 -name rgmii_rxc [get_ports rgmii_rxc]

六、板级验证

基于FPGA 以太网gmii_to_rgmii模块编写 附源码

到了这里,关于基于FPGA 以太网gmii_to_rgmii模块编写 附源码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 千兆以太网芯片88E1111 RGMII模式的FPGA驱动实现

    千兆以太网芯片88E1111 RGMII模式的FPGA驱动实现 在网络应用领域,千兆以太网已经成为主流,而88E1111作为一款先进的千兆以太网芯片,其驱动实现对于网络设备的性能和稳定性有着至关重要的影响。本文将介绍在RGMII模式下,如何实现88E1111芯片在FPGA上的驱动。 一、准备工作

    2024年01月22日
    浏览(59)
  • 基于FPGA的以太网相关文章导航

      首先需要了解以太网的一些接口协议标准,常见的MII、GMII、RGMII时序,便于后续开发。     【必读】从MII到RGMII,一文了解以太网PHY芯片不同传输接口信号时序!   介绍一款比较老的以太网PHY芯片88E1518,具有RGMII接口,分析该芯片的原理图和内部寄存器的配置方式

    2024年04月14日
    浏览(42)
  • 基于UDP协议的千兆以太网传输(FPGA)

    @[TOC]基于UDP协议的千兆以太网传输(FPGA) UDP协议是一种基于无连接协议,即发送端发送数据无需确认接收端是否存在;接收端收到数据后也无需给发送端反馈是否收到,所以UDP在数据发送过程中允许丢失一两包数据。用于对丢包不严格的场合,比如视频流,偶有一两帧的丢

    2024年02月12日
    浏览(69)
  • 基于FPGA的以太网传输图片通过HDMI显示(含源码)

      在此之前,已经讲解过HDMI、UDP、DDR3等模块的使用,前文在使用HDMI显示图片时,由于没有讲解DDR3,使用FPGA内部的RAM存储图像数据,因为FPGA片上RAM的资源有限,导致最终显示放大的图片失真严重。   本文通过DDR3存储整张图片的数据,然后通过HDMI在显示器上进行显示,

    2024年03月27日
    浏览(56)
  • 基于FPGA的百兆以太网通信(一)——MDIO配置PHY芯片

     一、以太网简介   之前提了个引子,接下来我会分享一下基于FPGA的百兆以太网通信学习过程。第一部分是对于以太网PHY芯片的配置和状态读取。   一般来说,FPGA以太网通信是需要外接的PHY芯片的,目前的很多FPGA出厂的底板上已经焊好了PHY芯片,所以这一点是比较方便的。

    2024年04月10日
    浏览(55)
  • FPGA以太网入门(一)——MDIO接口读写测试实验(基于紫光同创)

    此篇为专栏《紫光同创FPGA开发笔记》的第五篇,记录我的学习 FPGA 的一些开发过程和心得感悟,刚接触 FPGA 的朋友们可以先去此博客 《FPGA零基础入门学习路线》来做最基础的扫盲。 本篇内容基于笔者实际开发过程和正点原子资料撰写,将会详细讲解此 FPGA 实验的全流程,

    2024年04月15日
    浏览(64)
  • FPGA以太网入门(二)——ARP测试实验(基于紫光同创,含原语介绍)

    此篇为专栏《紫光同创FPGA开发笔记》的 第六篇 ,同时也是 FPGA 以太网入门 的 第二篇 ,记录我的学习 FPGA 的一些开发过程和心得感悟,刚接触 FPGA 的朋友们可以先去此博客 《FPGA零基础入门学习路线》来做最基础的扫盲。 本篇内容基于笔者实际开发过程和正点原子资料撰写

    2024年02月20日
    浏览(52)
  • FPGA实现以太网(一)——以太网简介

    以太网(Ethernet)是当今现有局域网采用的最通用的通信协议标准, 该标准定义了在局域网中采用的电缆类型和信号处理方法。 以太网凭借其成本低、通信速率高、抗干扰性强等优点被广泛应用在网络远程监控、 交换机、工业自动化等对通信速率要求较高的场合。 以太网是一

    2024年02月03日
    浏览(50)
  • 基于FPGA的GMII与RGMII接口相互转换(包含源工程文件)

      这段时间通过FPGA把ARP、ICMP、UDP协议全部通过FPGA实现了一遍,本来本文打算记录一下arp协议的,但在此之前应该先解决RGMII接口与GMII接口的转换问题。   经过前文讲解,开发板上使用的以太网PHY芯片是88R1518,原理图如下所示,留给用户的是RGMII双沿传输数据,时钟频率

    2024年03月18日
    浏览(83)
  • FPGA之以太网详解

    以太网(Ethernet)是当今局域网采用的最通用的局域网标准。它规定了包括物理层的连线,电子信号和介质访问协议的内容。它具有成本低,通信速率快,抗干扰性强的特点。 以太网主要分为: 标准以太网:10Mbit/s 快速以太网:100Mbit/s 千兆以太网:1000Mbit/s 以太网的接口主要

    2024年02月09日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包