zynq的PS端ENET网口引出到EMIO的PL引脚
参考1:
参考2:FPGA 控制 RGMII 接口 PHY芯片基础 丰科卓辰 2024-09-10 07:00 北京
https://baijiahao.baidu.com/s?id=1809712014208343972&wfr=spider&for=pc
PS端的ENET网口可以选择从MIO引出或EMIO引出,MIO引出是RGMII接口,具有固定的引脚,不需要在约束中进行引脚分配,使用比较简单。EMIO引出则比较灵活,可以引出到PL端的引脚。

但是引出为EMIO时,只能使用GMII接口,如果外部连接RGMII的PHY芯片,则需要GMII to RGMII的接口转换IP
RGMII比GMII使用更少的信号,主要使用时钟双沿采样把数据从8位减少到4位,控制从2为减少到1位,tx_en和tx_er合并成tx_ctrl,rx_和rx_er合并成rx_ctrl。不论GMII还是RGMII,tx_clk和rx_clk都是125MHz,125MHz8bit = 125MHz4bit*2 = 1000Mbit/s:

IP核按照以下配置:


时钟需要FCLK_CLK1输出200MHz


复位需要高电平复位:tx_reset和rx_reset都连接到peripheral_reset:

输出只需要GMII和MDIO即可,MDIO要分成3个信号,最后在顶层合并为inout信号。

其中双向引脚mdio在内部模块中全部使用3个引脚:
input MDIO_PHY_0_mdio_i;
output MDIO_PHY_0_mdio_o;
output MDIO_PHY_0_mdio_t;
在最外层合并为1个引脚:
IOBUF MDIO_PHY_0_mdio_iobuf
(
.I(MDIO_PHY_0_mdio_o),
.IO(MDIO_PHY_0_mdio_io),
.O(MDIO_PHY_0_mdio_i),
.T(MDIO_PHY_0_mdio_t)
);
从上边的时序图分析,数据在时钟的边沿变化。因此如果不做额外处理,接收端无法稳定采样。为了解决这一问题,常见的做法是为时钟信号添加延时,使其边沿对准数据总线的稳定区间。可以在控制器端、PCB走线以及PHY芯片内部添加时钟偏移,本文使用最后一种方式实现。

在第三阶段中添加延迟。数据发送方向,FPGA侧的TX_CLK信号不需要额外处理,也就是说FPGA发送与数据边沿对齐的时钟信号。TXD和TX_CLK信号波形如图。

PHY内部会调整TX_CLK,使之能够稳定采样TXD。数据接收方向,由于RX_CLK由PHY提供,PHY芯片直接产生与数据中心对齐的时钟信号。RXD和RX_CLK信号波形如图。

可见,使PHY芯片工作在延迟模式下时,FPGA不需要添加额外的逻辑来保证稳定采样。发送方向直接将数据驱动时钟作为TX_CLK信号发送,接收方向直接利用RX_CLK对RXD信号采样。
在较高速设计场合下,输入输出接口部分很容易出现数据采样不稳定的现象。这时候就要通过Input delay,output delay约束以及STA来分析设计是否满足稳定采样需求。input/output delay是指数据相对于时钟的延迟,只有设置好上述两个数值,综合工具才会往正确的方向优化并给出合理的时序报告。
FPGA与RGMII接口的PHY芯片之间的时序关系按照数据接口同步和数据采样方式属于源同步DDR采样。input delay约束对应接收方向,时序关系是中心对齐。output delay约束对应发送方向,时序关系是边沿对齐。前者由于很多时候不知道上游器件Tcko信息,会使用示波器测量有效数据窗口来计算。而后者因为是边沿对齐,通过示波器测量抖动窗口并使用skew based method计算。这部分笔者还没有亲身实践过,若有误欢迎指出。
增加以下约束:

set_property PACKAGE_PIN G21 [get_ports MDIO_PHY_0_mdc]
set_property PACKAGE_PIN H22 [get_ports MDIO_PHY_0_mdio_io]
set_property PACKAGE_PIN A22 [get_ports {RGMII_0_rd[0]}]
set_property PACKAGE_PIN A18 [get_ports {RGMII_0_rd[1]}]
set_property PACKAGE_PIN A19 [get_ports {RGMII_0_rd[2]}]
set_property PACKAGE_PIN B20 [get_ports {RGMII_0_rd[3]}]
set_property PACKAGE_PIN A21 [get_ports RGMII_0_rx_ctl]
set_property PACKAGE_PIN B19 [get_ports RGMII_0_rxc]
set_property PACKAGE_PIN E21 [get_ports {RGMII_0_td[0]}]
set_property PACKAGE_PIN F21 [get_ports {RGMII_0_td[1]}]
set_property PACKAGE_PIN F22 [get_ports {RGMII_0_td[2]}]
set_property PACKAGE_PIN G20 [get_ports {RGMII_0_td[3]}]
set_property PACKAGE_PIN G22 [get_ports RGMII_0_tx_ctl]
set_property PACKAGE_PIN D21 [get_ports RGMII_0_txc]
set_property PACKAGE_PIN M17 [get_ports UART_0_0_rxd]
set_property PACKAGE_PIN L17 [get_ports UART_0_0_txd]
set_property IOSTANDARD LVCMOS33 [get_ports MDIO_PHY_0_mdc]
set_property IOSTANDARD LVCMOS33 [get_ports MDIO_PHY_0_mdio_io]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_rd[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_rx_ctl]
set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_rxc]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {RGMII_0_td[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_tx_ctl]
set_property IOSTANDARD LVCMOS33 [get_ports RGMII_0_txc]
set_property IOSTANDARD LVCMOS33 [get_ports UART_0_0_rxd]
set_property IOSTANDARD LVCMOS33 [get_ports UART_0_0_txd]
set_property SLEW FAST [get_ports {RGMII_0_td[0]}]
set_property SLEW FAST [get_ports {RGMII_0_td[1]}]
set_property SLEW FAST [get_ports {RGMII_0_td[2]}]
set_property SLEW FAST [get_ports {RGMII_0_td[3]}]
set_property SLEW FAST [get_ports RGMII_0_tx_ctl]
set_property SLEW FAST [get_ports RGMII_0_txc]
create_clock -period 8.000 -name RGMII_0_rxc -waveform {0.000 4.000} [get_ports RGMII_0_rxc]
set_clock_groups -logically_exclusive -group [get_clocks -include_generated_clocks {gmii_clk_25m_out gmii_clk_2_5m_out}] -group [get_clocks -include_generated_clocks gmii_clk_125m_out]
