最近在Zynq上做千兆以太网,RGMII接口的TXC和TXD之间要求2ns的PCB走线补偿,但我在Vivado里加了set_input_delay和set_output_delay之后时序还是红。网上说要用IDELAYE2做IOB延迟,但具体是放在读数据还是写数据方向?有没有大佬分享一个能直接过的约束模板?另外,用国产紫光同创的FPGA做RGMII,Primitive和Xilinx差别大吗?
2026年了,FPGA工程师做千兆以太网,RGMII时序约束一直报错,IDELAY和IODELAY到底怎么配?
3 个回答

先别急着堆 IDELAYE2,你大概率是把方向搞混了。RGMII 的 2ns 补偿,核心是 TXC 相对 TXD/TXCTL 的沿对齐,而不是数据本身延迟多少。Vivado 里你写的 set_output_delay -clock [get_clocks {tx_clk}] -max 2.0 -min 0.2,这个方向是对的,但很多人漏了关键一步:TXC 必须由 ODDR 原语从内部时钟直接产生,而且要和数据走同一条路径。如果你只是把 TXC 当普通信号输出,约束写得再漂亮也会因为时钟树偏差报红。IDELAYE2 一般只用在 RX 侧,补偿的是 PCB 走线导致的采样窗口偏移——也就是对方发的数据相对 TXC 到达你这边时,可能不在理想位置。Zynq 上常见做法是 RX 数据、RXCTL 各挂一个 IDELAYE2,TXC 不延迟,然后用内部逻辑找边沿。你如果 TX 方向也加 IDELAY,反而会引入额外抖动,约束更难收敛。排查顺序建议:先确认 TXC 是不是通过 ODDR 输出,且约束里有没有对 TXC 单独设 false path 或 set_output_delay;再看 RX 侧约束的 -clock 是哪个时钟域,RGMII 读方向要用虚拟时钟(create_clock -name rgmii_rx_clk -period 8),不能直接用内部 125M 时钟。国产紫光同创那边,Primitive 名字不同,比如 IDELAYE2 对应的是 IDELAY,ODDR 对应 ODDR 但配置参数有差异,建议直接查他们官方例程里的 rgmii 工程,别硬套 Xilinx 写法。你现在的报错是 setup 还是 hold 违例?如果是 hold,先查 min delay 是不是设错了,RGMII 的 hold 要求其实很宽松,0.2ns 一般够用。最后给个能过的模板思路:TX 方向约束写死后,在实现阶段看 report_timing_summary 里 RGMII 接口的 slack,如果还是红,大概率是 PCB 上走线长度没匹配,不是约束问题。你用的是 Zynq 哪款型号?不同速度等级对 IO delay 的裕量影响挺大的。

你这个问题我遇到过,最后发现是约束里时钟定义错了。RGMII 的 TX 方向,TXC 和内部时钟是同一个,但 RX 方向必须单独建一个虚拟时钟,周期 8ns,然后 set_input_delay 全部挂到虚拟时钟上。否则 Vivado 会默认用内部 125M 做分析,hold 和 setup 全乱。IDELAYE2 确实只放 RX,而且建议先用 0 延迟跑通功能,再加延迟调采样点。紫光同创那边,原语名称是 IDELAY 和 ODELAY,参数里没有 Xilinx 的 CINVCTRL 这类位,但用法类似。你先把 Xilinx 侧跑通,再移植过去会快很多。另外注意,Zynq 的 PS 端 GEM 和 PL 端 RGMII 约束方式不同,如果你用的是 PS 的 MIO 引脚,那根本不需要 IDELAY,直接改设备树就行。你现在是 PL 实现还是 PS 复用?这个决定后续排查方向。

看你这描述,大概率不是IDELAY配错,而是时钟约束的根上就歪了。先说结论:IDELAYE2只放RX方向,TX方向靠ODDR和set_output_delay就够了,别在写数据那侧加IODELAY,加了反而把路径搞复杂。
你现在的报错,我猜十有八九是Vivado把TXC当成了普通数据信号,而不是时钟。RGMII的TXC在FPGA内部必须用ODDR原语从125M时钟直接产生,输出端接到TXC引脚,同时TXD和TXCTL也走ODDR,这样TXC和数据的路径起点都是同一个时钟,时序工具才能正确计算那2ns的偏移。如果你只是assign tx_c = clk_125m这种写法,约束里写的set_output_delay -clock [get_clocks {tx_clk}]根本匹配不到真正的时钟树,时序全乱。
读方向那边,set_input_delay要挂在虚拟时钟上,周期8ns,因为RX的TXC是外部芯片发过来的,不是FPGA内部时钟。常见模板是create_clock -name rgmii_rx_clk -period 8,然后set_input_delay -clock rgmii_rx_clk -max 2.0 [get_ports {rgmii_rxd rgmii_rxctl}],再配set_input_delay -min 0.2。这里有个坑:很多人忘了给虚拟时钟加约束,导致input delay没地方挂,Vivado直接忽略。
IDELAYE2的用法,建议先设0延迟跑功能,确认数据能通,再用chipscope或者ILA看采样点位置,逐步加tap数。一般来说,Zynq上RX数据线和RXCTL各挂一个IDELAYE2,tap值在4到8之间比较常见,但具体取决于你的PCB走线长度。别一上来就按网上模板抄,每块板子的走线不一样。
至于紫光同创,Primitive名称确实不同,IDELAY和ODELAY的参数位宽、控制方式都有差异,但时序模型思路一样。我的建议是先把Xilinx侧调通,再对照国产手册移植,别两头同时搞,容易混。另外,如果你用的是Zynq PS端的GEM而不是PL逻辑,那根本不需要IDELAY,改设备树里的tx-internal-delay和rx-internal-delay就行,别在PL里折腾了。
你现在是PL自己写MAC还是用的PS的GEM?这个得先说清楚,不然约束方向差很多。
发表回答
登录后可在本页底部提交回答