笔者使用的开发板是米联客zynq UitraScale+ xczu4ev-sfvc784-2-i开发板进行测试
由于米联客协议族源码不开源,自己写了一个简易的以太网接口转换模块只支持1000M速率。
一、接口框图:(引用原子哥)
二、RGMII接口时序简介:
(1)接收时序(PHY>FPGA)
RXC 的上下边沿与 RXD 和 RX_CTL 信号对齐,相位相同。(非延时模式)
RXC 的上下边沿与 RXD 和 RX_CTL 信号的中间位置对齐,相位相差90度(延时模式)
RXC 的时钟周期为 8ns,单个高电平或者低电平为 4ns, RXC 相对于 RXD 和 RX_CTL 延时约 2ns。
(2)发送时序(FPGA>PHY)
TXC 的上下边沿与 TXD 和 TX_CTL 信号对齐,相位相同。 (非延时模式)
RGMII 发送端口在 TXC 时钟的上升沿传输 TXD 的低 4 位和 TX_CTL 的使能信号;
下降沿传输 TXD 的高 4 位和 TX_CTL 的错误信号(实际上是使能信号和错误信号的异或值); RGMII 接收端口在RXC 时钟的上升沿传输 RXD 的低 4 位和 RX_CTL 的使能信号;
下降沿传输RXD 的高 4 位和RX_CTL 的错误信号(实际上是使能信号和错误信号的异或值)。(延时模式)
注意:笔者芯片接收时序为延时模式,发送时序为正常模式,具体模式需参考相应原理图引脚上下拉判断,也可通过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资源配置:
顶层例化使用
//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
);
五、仿真
有点乱码不影响查看文章来源:https://www.toymoban.com/news/detail-461206.html
`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
注意:发送时钟并未体现数据中间采样是因为时钟输出采用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模块编写 附源码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!